Plan

20200203

From meeting with Tom Fitzgerald on 26 November 2019:

• Introgression: - Create giant population VCF - choose the datasets. Just a case of merging some VCFs. - Get some Indonesian medaka • LD decay: - LD plots - per chromosome. - Heatmap per chromosome? • Fst plot

Setup

Create directory structure and clone repo

Working directory here: /hps/research1/birney/users/ian/mikk_paper

# move to working directory
homehps
cd mikk_paper
# clone git repository
git clone https://github.com/Ian-Brettell/mikk_genome.git
# create directory for VCFs
mkdir vcfs

Pull across MIKK Panel VCF

cp /nfs/research1/birney/projects/medaka/inbred_panel/medaka-alignments-release-94/vcf/medaka_inbred_panel_ensembl_new_reference_release_94.vcf* vcfs

Key file for cram ID to line ID

mikk_genome/data/20200206_cram_id_to_line_id.txt

Remove duplicates and non-panel lines

# Find duplicates
ssh ebi
homehps
cd mikk_paper/mikk_genome/
cat data/20200206_cram_id_to_line_id.txt | cut -f2 | cut -f1 -d"_" | sort | uniq -d

Note the following duplicates:

-106 -11 -117 -131 -132 -134 -135 -138 -14 -140 -141 -15 -23 -32 -39 -4 -40 -49 -59 -69 -7 -71 -72 -80 -84

Only take _1 sibling from pair, unless what is excluded is the only survivor based on mikk_behaviour/data/panel_1/20200109_panel_lines.txt.

Query whether we keep the lines that may have died out? Ask Felix.

Key file for no sibs

mikk_genome/data/20200206_cram2line_key_no-sibs.txt

Excluded IDs: mikk_genome/data/20200206_excluded_lines.txt

20200225

Full list of MIKK lines from Felix here: mikk_genome/data/20200210_panel_lines_full.txt

cat ~/Documents/Repositories/mikk_genome/data/20200210_panel_lines_full.txt cut -f1 -d"-" | sort | uniq -d
  • 106
  • 11
  • 117
  • 131
  • 132
  • 135
  • 14
  • 140
  • 23
  • 39
  • 4
  • 40
  • 59
  • 69
  • 72
  • 80

List with no sibling lines here: mikk_genome/data/20200227_panel_lines_no-sibs.txt. 64 lines total.

Excluded IDs here: mikk_genome/data/20200227_panel_lines_excluded.txt. 16 lines total.

Replace all dashes with underscores to match cram2line key file

sed 's/-/_/g' data/20200227_panel_lines_no-sibs.txt > data/20200227_panel_lines_no-sibs_us.txt  

Extract the lines to keep from the key file.

awk  'FNR==NR {f1[$0]; next} $2 in f1' data/20200227_panel_lines_no-sibs_us.txt data/20200206_cram_id_to_line_id.txt > data/20200227_cram2line_no-sibs.txt

Has 66 lines instead of 63 (because we’re missing 130-2), so there must be duplicates. Find out which ones:

cat data/20200227_cram2line_no-sibs.txt | cut -f2 | cut -f1 -d"_" | sort | uniq -d

32 71 84

Manually removed (data/20200227_duplicates_excluded.txt):

• 24271_7#5 32_2 • 24271_8#4 71_1 • 24259_1#1 84_2

Final version: data/20200227_cram2line_no-sibs.txt

Final version, cram IDs only:

Create filtered VCF

Rename samples using BCFTOOLS

# create list of CRAM IDs in VCF
bcftools query -l vcfs/medaka_inbred_panel_ensembl_new_reference_release_94.vcf > tmp.txt
# confirm that it's in the same order as the column in the line IDs file
cut -f1 mikk_genome/data/20200206_cram_id_to_line_id.txt | tail -n+2 > tmp2.txt
# bash script to compare
file1="tmp.txt"
file2="tmp2.txt"

if cmp -s "$file1" "$file2"; then
    printf 'The file "%s" is the same as "%s"\n' "$file1" "$file2"
else
    printf 'The file "%s" is different from "%s"\n' "$file1" "$file2"
fi
# clean up
rm tmp*

# create file with no header
tail -n+2 mikk_genome/data/20200206_cram_id_to_line_id.txt > mikk_genome/data/20200203_cram2line_no-header.txt
# replace tab with space
sed 's/\t/ /g' mikk_genome/data/20200203_cram2line_no-header.txt > tmp.txt
mv tmp.txt mikk_genome/data/20200203_cram2line_no-header.txt

# Rename samples with BCFTOOLS
bcftools reheader --output-file vcfs/panel_line-ids.vcf --samples mikk_genome/data/20200203_cram2line_no-header.txt vcfs/medaka_inbred_panel_ensembl_new_reference_release_94.vcf
# test
bcftools query -l  vcfs/panel_line-ids.vcf
#[E::bcf_hdr_add_sample] Duplicated sample name '84_2'
#[E::bcf_hdr_add_sample] Duplicated sample name '141_3'
#[E::bcf_hdr_add_sample] Duplicated sample name '32_2'
#[E::bcf_hdr_add_sample] Duplicated sample name '71_1'
#Failed to open vcfs/panel_line-ids.vcf: could not parse header

# create no-sibs file with CRAM ID only
cut -f1 mikk_genome/data/20200227_cram2line_no-sibs.txt > mikk_genome/data/20200227_cram2line_no-sibs_cram-only.txt
# pull out only samples to be included, then recode
bcftools view --output-file vcfs/panel_no-sibs.vcf --samples-file mikk_genome/data/20200227_cram2line_no-sibs_cram-only.txt vcfs/medaka_inbred_panel_ensembl_new_reference_release_94.vcf
# SUCCESS
# recode
bcftools reheader --output vcfs/panel_no-sibs_line-ids.vcf --samples mikk_genome/data/20200227_cram2line_no-sibs.txt vcfs/panel_no-sibs.vcf
# compress
## option 1: bgzip vcfs/panel_no-sibs_line-ids.vcf
## option 2:
bcftools view --output-type z --output-file vcfs/panel_no-sibs_line-ids.vcf.gz vcfs/panel_no-sibs_line-ids.vcf
# create index
bcftools index --tbi vcfs/panel_no-sibs_line-ids.vcf.gz

Get stats on no-sibs VCF

mkdir stats
bcftools stats vcfs/panel_no-sibs_line-ids.vcf.gz > stats/20200305_panel_no-sibs.txt

• number of samples: 63 • number of records: 29,161,024 • number of no-ALTs: 0 • number of SNPs: 24,031,673 • number of MNPs: 0 • number of indels: 5575994 • number of others: 449159 • number of multiallelic sites: 2957366 • number of multiallelic SNP sites: 1434908

• ts: 12640470 • tv: 11886484
• ts/tv: 1.06

Split by chromosome

Get reference

mkdir refs

cp /nfs/research1/birney/projects/medaka/inbred_panel/medaka-alignments-release-94/ref/Oryzias_latipes.ASM223467v1* refs/

Split by chromosome

mkdir vcfs/split_by_chr

for i in $(seq 1 24); do
  bsub -o log/split_by_chr_$i.out -e log/split_by_chr_$i.err \
  "bcftools filter \
    --regions $i \
    --output-type z \
    --output vcfs/split_by_chr/panel_no-sibs_chr-$i.vcf.gz \
    vcfs/panel_no-sibs_line-ids.vcf.gz";
done  

Get stats per chromosome

mkdir stats/by_chr

for i in $(seq 1 24); do
  bsub -o log/stats_by_chr_$i.out -e log/stats_by_chr_$i.err \
  "bcftools stats \
    vcfs/split_by_chr/panel_no-sibs_chr-$i.vcf.gz > stats/by_chr/$i.txt";
done 

Run LD

VCFtools

mkdir ld
mkdir ld/20200305_panel_maf-0.03_window-50kb

for i in $(seq 1 24); do
  bsub -M 30000 -n 8 -o log/ld_$i.out -e log/ld_$i.err \
  "vcftools \
    --gzvcf vcfs/split_by_chr/panel_no-sibs_chr-$i.vcf.gz \
    --geno-r2 \
    --ld-window-bp 50000 \
    --maf 0.03 \
    --out ld/20200305_panel_maf-0.03_window-50kb/$i";
done  

# creates huge files (~10G). Take random 1M lines
## create set up directory
mkdir ld/20200305_panel_maf-0.03_window-50kb_thinned
## 
for i in $(seq 1 24); do
  bsub -o log/ld_trim_$i.out -e log/ld_trim_$i.err \
  "head -1 > ld/20200305_panel_maf-0.03_window-50kb_thinned/$i\_1m.txt && \
  shuf -n 1000000 ld/20200305_panel_maf-0.03_window-50kb/$i.geno.ld >> ld/20200305_panel_maf-0.03_window-50kb_thinned/$i\_1m.txt";
done

head -1 > ld/20200305_panel_maf-0.03_window-50kb_thinned/24_1m.txt
shuf -n 1000000 ld/20200305_panel_maf-0.03_window-50kb/24.geno.ld >> ld/20200305_panel_maf-0.03_window-50kb_thinned/24_1m.txt

Find missing sites

for i in $(seq 1 24); do
  bsub -M 20000 -n 4 -o log/missing_$i.out -e log/missing_$i.err \
  "vcftools \
    --gzvcf vcfs/split_by_chr/panel_no-sibs_chr-$i.vcf.gz \
    --missing-site \
    --out missing/$i";
done

Rename full run

Create new cram2lineid file with duplicates edited

# Find duplicates
cut -f2 mikk_genome/data/20200206_cram_id_to_line_id.txt | sort | uniq -cd

• 2 141_3 • 2 32_2 • 2 71_1 • 2 84_2

Edited them as follows:

• 2 141_3-2 • 2 32_2-2 • 2 71_1-2 • 2 84_2-2

Saved here: mikk_genome/data/20200305_cram2line_full_dupes-edited.txt

Rename full VCF

# rehead
bcftools reheader \
  --output vcfs/full-run_line-ids.vcf \
  --samples mikk_genome/data/20200305_cram2line_full_dupes-edited.txt \
  vcfs/medaka_inbred_panel_ensembl_new_reference_release_94.vcf
  
# compress
bcftools view \
  --output-type z \
  --output-file vcfs/full-run_line-ids.vcf.gz \
  vcfs/full-run_line-ids.vcf
  
# index
bcftools index \
  --tbi vcfs/full-run_line-ids.vcf.gz

20200602

Get LD plots using R.

Import data

sort(as.integer(names(data_list)))
 [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

Get distance measure

data_list <- lapply(data_list, function(chr){
  chr$distance_kb <- abs(chr$snp_1 - chr$snp_2) / 1000
  return(chr)
})

Collapse into single DF

data_df <- dplyr::bind_rows(data_list)

Plot by chr

# TEST
test_df <- dplyr::sample_n(data_df, 10000)

test_df %>% 
  ggplot(aes(distance_kb, r2)) +
  geom_point(size = 0.1, alpha = 0.005) +
  geom_smooth(size = 0.5) +
  theme_bw() +
  facet_wrap(~chr, nrow = 6, ncol = 4) +
  xlab("Distance between SNPs (bp)") +
  ylab(parse(text = "r^2"))

NA
NA
# TRUE
data_df %>% 
  ggplot(aes(distance_kb, r2)) +
  geom_point(size = 0.1, alpha = 0.005) +
  geom_smooth(size = 0.5) +
  theme_bw() +
  facet_wrap(~chr, nrow = 6, ncol = 4) +
  xlab("Distance between SNPs (kb)") +
  ylab(parse(text = "r^2"))

ggsave(filename = paste("20200602_ld_decay_subset_allchr", ".png", sep = ""),
       device = "png",
       path = "~/Documents/Docs/medaka\ pics/20200602_mikk_genome/",
       width = 15,
       height = 15,
       units = "cm",
       dpi = 500)

Find out what the SNPs have in common

# how many?
length(which(data_df$count == 63))
[1] 9657665

Plot just those

ggsave(filename = paste("20200603_ld_decay_subset_allchr_allsmpls", ".png", sep = ""),
       device = "png",
       path = "~/Documents/Docs/medaka\ pics/20200602_mikk_genome/",
       width = 20,
       height = 20,
       units = "cm",
       dpi = 500)

Take a look at those with r^2 of 1 greater than 20kb away

View(full_call_df %>% dplyr::filter(distance > 20))

Looking at individual SNPs in the VCF using grep, most of them have low MAFs (3 < x < 5). Run LD calcs again using threshold of 5%.

mkdir ld/20200305_panel_maf-0.05_window-50kb

for i in $(seq 1 24); do
  bsub -M 30000 -n 8 -o log/ld_$i.out -e log/ld_$i.err \
  "vcftools \
    --gzvcf vcfs/split_by_chr/panel_no-sibs_chr-$i.vcf.gz \
    --geno-r2 \
    --ld-window-bp 50000 \
    --maf 0.05 \
    --out ld/20200305_panel_maf-0.05_window-50kb/$i";
done  

Filter files on cluster for only those with full calls

mkdir ld/20200305_panel_maf-0.03_window-50kb_full-calls

for i in $(find ld/20200305_panel_maf-0.03_window-50kb/23.geno.ld); do
  name=$(basename $i | cut -f1 -d".");
  awk_subscript=$(echo "awk '\$4 == 63' $i >> ld/20200305_panel_maf-0.03_window-50kb_full-calls/$name.txt");
  script=$(echo "head -1 $i > ld/20200305_panel_maf-0.03_window-50kb_full-calls/$name.txt; $awk_subscript");
  bsub -M 30000 -o log/ld_full-calls_$name.out -e log/ld_full-calls_$name.err $(printf $script);
done
# Can't do it like this - has a problem with the awk script. Have to do it in one job:

for i in $(find ld/20200305_panel_maf-0.03_window-50kb/*); do
  name=$(basename $i | cut -f1 -d".");
  head -1 $i > ld/20200305_panel_maf-0.03_window-50kb_full-calls/$name.txt;
  awk '$4 == 63' $i >> ld/20200305_panel_maf-0.03_window-50kb_full-calls/$name.txt
done  

Run R script to create plots

R script here: mikk_genome/code/scripts/20200602_ld_decay_plot.R

for i in $(find ld/20200305_panel_maf-0.03_window-50kb_full-calls/* | head -1); do
  date_today=$(date +'%Y%m%d');
  name=$(basename $i | cut -f1 -d".");
  bsub -M 50000 -o log/$date_today\_$name\_plotld.out -e log/$date_today\_$name\_plotld.err "Rscript --vanilla mikk_genome/code/scripts/20200602_ld_decay_plot.R $i plots/ $date_today";
done
# Can't handle it with 50MB memory

Try with new MAF 0.05 calls

for i in $(find ld/20200305_panel_maf-0.05_window-50kb_full-calls/* | head -1); do
  date_today=$(date +'%Y%m%d');
  name=$(basename $i | cut -f1 -d".");
  bsub -M 50000 -o log/$date_today\_plotld_$name.out -e log/$date_today\_plotld_$name.err "Rscript --vanilla mikk_genome/code/scripts/20200602_ld_decay_plot.R $i plots/ $date_today";
done
# STILL has the line at R^2 == 1!!

20200707

Try all again, this time removing indels.

Setup

mkdir ld/20200707_panel_maf-0.05_window-50kb

Get LD stats using VCFTools

for i in $(find vcfs/split_by_chr/*); do
  date_today=$(date +'%Y%m%d');
  chr=$(basename $i | awk -F'-' '{print $3}' | sed 's/.vcf.gz//');
  bsub -M 30000 -o log/$date_today\_ld_$chr.out -e log/$date_today\_ld_$chr.err \
  "vcftools \
    --gzvcf $i \
      --ld-window-bp 50000 \
      --maf 0.05 \
      --max-alleles 2 \
      --min-alleles 2 \
      --remove-indels \
      --geno-r2 \
      --out ld/20200707_panel_maf-0.05_window-50kb/$chr";
done

Create new VCF with only sites that have no missing genotypes

# needs --recode flag!!
vcftools \
  --gzvcf vcfs/panel_no-sibs_line-ids.vcf.gz \
  --max-missing 1 \
  --recode \
  --stdout > vcfs/panel_no-sibs_line-ids_no-missing.vcf
## compress
bcftools view --output-type z --output-file vcfs/panel_no-sibs_line-ids_no-missing.vcf.gz vcfs/panel_no-sibs_line-ids_no-missing.vcf
# create index
bcftools index --tbi vcfs/panel_no-sibs_line-ids_no-missing.vcf.gz

• number of samples: 63 • number of records: 20,086,433 • number of no-ALTs: 0 • number of SNPs: 16,956,405 • number of MNPs: 0 • number of indels: 3329681 • number of others: 0 • number of multiallelic sites: 1333182 • number of multiallelic SNP sites: 260770

Rerun LD stats with max MAF of 99 (to exclude variants where the whole panel is 1/1 for the ALT)

# make directory
mkdir ld/20200707_panel_maf-0.05_window-50kb_no-missing_maf-max-0.99/
# run
for i in $(seq 1 24); do
  date_today=$(date +'%Y%m%d');
  bsub -M 30000 -o log/$date_today\_ld_maf-max_$chr.out -e log/$date_today\_ld_maf-max_$chr.err \
  "vcftools \
    --gzvcf vcfs/panel_no-sibs_line-ids_no-missing.vcf.gz \
      --ld-window-bp 50000 \
      --chr $i \
      --maf 0.05 \
      --max-maf 0.99 \
      --max-alleles 2 \
      --min-alleles 2 \
      --remove-indels \
      --geno-r2 \
      --out ld/20200707_panel_maf-0.05_window-50kb_no-missing_maf-max-0.99/$i";
done

Thin

## create set up directory
mkdir ld/20200707_panel_maf-0.05_window-50kb_no-missing_maf-max-0.99_thinned/
## Extract random 1M pairs
for i in $(seq 1 24); do
  date_today=$(date +'%Y%m%d');
  bsub -o log/$date_today\_ld_trim_$i.out -e log/$date_today\_ld_trim_$i.err \
  "head -1 ld/20200707_panel_maf-0.05_window-50kb_no-missing_maf-max-0.99/$i.geno.ld > ld/20200707_panel_maf-0.05_window-50kb_no-missing_maf-max-0.99_thinned/$i\_1m.txt && \
  shuf -n 1000000 ld/20200707_panel_maf-0.05_window-50kb_no-missing_maf-max-0.99/$i.geno.ld >> ld/20200707_panel_maf-0.05_window-50kb_no-missing_maf-max-0.99_thinned/$i\_1m.txt";
done
## send to local
scp -r brettell@ebi:/hps/research1/birney/users/ian/mikk_paper/ld/20200707_panel_maf-0.05_window-50kb_no-missing_maf-max-0.99_thinned/ ~/Documents/Data/20200707_mikk_ld

Import data

data_files <- list.files("~/Documents/Data/20200707_mikk_ld/20200707_panel_maf-0.05_window-50kb_no-missing_maf-max-0.99_thinned",
                         full.names = T)
data_files_trunc <- list.files("~/Documents/Data/20200707_mikk_ld/20200707_panel_maf-0.05_window-50kb_no-missing_maf-max-0.99_thinned")
data_files_trunc <- gsub("_1m.txt", "", data_files_trunc)

data_list <- lapply(data_files, function(data_file){
  df <- read.delim(data_file,
                   sep = "\t",
                   header = T)
  names(df) <- c("chr", "snp_1", "snp_2", "count", "r2")
  return(df)
})
names(data_list) <- as.integer(data_files_trunc)

# reorder
data_list <- data_list[order(as.integer(names(data_list)))]

Get distance measure

data_list <- lapply(data_list, function(chr){
  chr$distance_kb <- abs(chr$snp_1 - chr$snp_2) / 1000
  return(chr)
})

Collapse into single DF

data_df <- dplyr::bind_rows(data_list)

Plot by chr

# TEST
test_df <- dplyr::sample_n(data_df, 10000)

test_df %>% 
  ggplot(aes(distance_kb, r2)) +
  geom_point(size = 0.1, alpha = 0.005) +
  geom_smooth(size = 0.5) +
  theme_bw() +
  facet_wrap(~chr, nrow = 6, ncol = 4) +
  xlab("Distance between SNPs (kb)") +
  ylab(parse(text = "r^2"))

NA
NA
# TRUE
data_df %>% 
  ggplot(aes(distance_kb, r2)) +
  geom_point(size = 0.1, alpha = 0.005) +
  geom_smooth(size = 0.5) +
  theme_bw() +
  facet_wrap(~chr, nrow = 6, ncol = 4) +
  xlab("Distance between SNPs (kb)") +
  ylab(parse(text = "r^2"))

ggsave(filename = paste("20200708_ld_decay_subset_allchr_max_maf_0.99", ".png", sep = ""),
       device = "png",
       path = "~/Documents/Docs/medaka\ pics/20200602_mikk_genome/",
       width = 15,
       height = 15,
       units = "cm",
       dpi = 500)

Looks better - with reduced density up the top for some chromosomes - but for others there are still strong lines with an r^2 of 1.

Try setting the max MAF at 0.5.

Rerun LD stats with max MAF of 0.5

# make directory
mkdir ld/20200707_panel_maf-0.05_window-50kb_no-missing_maf-max-0.50/
# run
for i in $(seq 1 24); do
  date_today=$(date +'%Y%m%d');
  bsub -M 30000 -o log/$date_today\_ld_maf-max_$chr.out -e log/$date_today\_ld_maf-max_$chr.err \
  "vcftools \
    --gzvcf vcfs/panel_no-sibs_line-ids_no-missing.vcf.gz \
      --ld-window-bp 50000 \
      --chr $i \
      --maf 0.05 \
      --max-maf 0.50 \
      --max-alleles 2 \
      --min-alleles 2 \
      --remove-indels \
      --geno-r2 \
      --out ld/20200707_panel_maf-0.05_window-50kb_no-missing_maf-max-0.50/$i";
done

Thin

## create set up directory
mkdir ld/20200707_panel_maf-0.05_window-50kb_no-missing_maf-max-0.50_thinned/
## Extract random 1M pairs
for i in $(seq 1 24); do
  date_today=$(date +'%Y%m%d');
  bsub -o log/$date_today\_ld_trim_$i.out -e log/$date_today\_ld_trim_$i.err \
  "head -1 ld/20200707_panel_maf-0.05_window-50kb_no-missing_maf-max-0.50/$i.geno.ld > ld/20200707_panel_maf-0.05_window-50kb_no-missing_maf-max-0.50_thinned/$i\_1m.txt && \
  shuf -n 1000000 ld/20200707_panel_maf-0.05_window-50kb_no-missing_maf-max-0.50/$i.geno.ld >> ld/20200707_panel_maf-0.05_window-50kb_no-missing_maf-max-0.50_thinned/$i\_1m.txt";
done
## send to local
scp -r brettell@ebi:/hps/research1/birney/users/ian/mikk_paper/ld/20200707_panel_maf-0.05_window-50kb_no-missing_maf-max-0.50_thinned/ ~/Documents/Data/20200707_mikk_ld

Import data

data_files <- list.files("~/Documents/Data/20200707_mikk_ld/20200707_panel_maf-0.05_window-50kb_no-missing_maf-max-0.50_thinned",
                         full.names = T)
data_files_trunc <- list.files("~/Documents/Data/20200707_mikk_ld/20200707_panel_maf-0.05_window-50kb_no-missing_maf-max-0.50_thinned")
data_files_trunc <- gsub("_1m.txt", "", data_files_trunc)
 
data_list <- lapply(data_files, function(data_file){
  df <- read.delim(data_file,
                   sep = "\t",
                   header = T)
  names(df) <- c("chr", "snp_1", "snp_2", "count", "r2")
  return(df)
})
names(data_list) <- as.integer(data_files_trunc)

# reorder
data_list <- data_list[order(as.integer(names(data_list)))]

Get distance measure

data_list <- lapply(data_list, function(chr){
  chr$distance_kb <- abs(chr$snp_1 - chr$snp_2) / 1000
  return(chr)
})

Collapse into single DF

data_df <- dplyr::bind_rows(data_list)

Plot

# TRUE
data_df %>% 
  ggplot(aes(distance_kb, r2)) +
  geom_point(size = 0.1, alpha = 0.005) +
  geom_smooth(size = 0.5) +
  theme_bw() +
  facet_wrap(~chr, nrow = 6, ncol = 4) +
  xlab("Distance between SNPs (kb)") +
  ylab(parse(text = "r^2"))

ggsave(filename = paste("20200709_ld_decay_subset_allchr_max-maf-0.50", ".png", sep = ""),
       device = "png",
       path = "~/Documents/Docs/medaka\ pics/20200602_mikk_genome/",
       width = 15,
       height = 15,
       units = "cm",
       dpi = 500)

Rerun LD stats with min MAF of 0.1 and max MAF of 0.9

# make directory
mkdir ld/20200707_panel_maf-0.10_window-50kb_no-missing_maf-max-0.90/
# run
for i in $(seq 1 24); do
  date_today=$(date +'%Y%m%d');
  bsub -M 30000 -o log/$date_today\_ld_maf-max_$chr.out -e log/$date_today\_ld_maf-max_$chr.err \
  "vcftools \
    --gzvcf vcfs/panel_no-sibs_line-ids_no-missing.vcf.gz \
      --ld-window-bp 50000 \
      --chr $i \
      --maf 0.10 \
      --max-maf 0.90 \
      --max-alleles 2 \
      --min-alleles 2 \
      --remove-indels \
      --geno-r2 \
      --out ld/20200707_panel_maf-0.10_window-50kb_no-missing_maf-max-0.90/$i";
done

Thin

## create set up directory
mkdir ld/20200707_panel_maf-0.10_window-50kb_no-missing_maf-max-0.90_thinned/
## Extract random 1M pairs
for i in $(seq 1 24); do
  date_today=$(date +'%Y%m%d');
  bsub -o log/$date_today\_ld_trim_$i.out -e log/$date_today\_ld_trim_$i.err \
  "head -1 ld/20200707_panel_maf-0.10_window-50kb_no-missing_maf-max-0.90/$i.geno.ld > ld/20200707_panel_maf-0.10_window-50kb_no-missing_maf-max-0.90_thinned/$i\_1m.txt && \
  shuf -n 1000000 ld/20200707_panel_maf-0.10_window-50kb_no-missing_maf-max-0.90/$i.geno.ld >> ld/20200707_panel_maf-0.10_window-50kb_no-missing_maf-max-0.90_thinned/$i\_1m.txt";
done
## send to local
scp -r brettell@ebi:/hps/research1/birney/users/ian/mikk_paper/ld/20200707_panel_maf-0.10_window-50kb_no-missing_maf-max-0.90_thinned/ ~/Documents/Data/20200707_mikk_ld


### NOTE: weird double header in chr14 file. Remove
head -1 ~/Documents/Data/20200707_mikk_ld/20200707_panel_maf-0.10_window-50kb_no-missing_maf-max-0.90_thinned/14_1m.txt > ~/Documents/Data/20200707_mikk_ld/20200707_panel_maf-0.10_window-50kb_no-missing_maf-max-0.90_thinned/14_1m.txt.tmp
grep -F -v "R^2" ~/Documents/Data/20200707_mikk_ld/20200707_panel_maf-0.10_window-50kb_no-missing_maf-max-0.90_thinned/14_1m.txt >> ~/Documents/Data/20200707_mikk_ld/20200707_panel_maf-0.10_window-50kb_no-missing_maf-max-0.90_thinned/14_1m.txt.tmp && mv ~/Documents/Data/20200707_mikk_ld/20200707_panel_maf-0.10_window-50kb_no-missing_maf-max-0.90_thinned/14_1m.txt.tmp ~/Documents/Data/20200707_mikk_ld/20200707_panel_maf-0.10_window-50kb_no-missing_maf-max-0.90_thinned/14_1m.txt

Import data

data_files <- list.files("~/Documents/Data/20200707_mikk_ld/20200707_panel_maf-0.10_window-50kb_no-missing_maf-max-0.90_thinned",
                         full.names = T)
data_files_trunc <- list.files("~/Documents/Data/20200707_mikk_ld/20200707_panel_maf-0.10_window-50kb_no-missing_maf-max-0.90_thinned")
data_files_trunc <- gsub("_1m.txt", "", data_files_trunc)

data_list <- lapply(data_files, function(data_file){
  df <- read.delim(data_file,
                   sep = "\t",
                   header = T)
  names(df) <- c("chr", "snp_1", "snp_2", "count", "r2")
#  df$snp_1 <- as.integer(df$snp_1)
#  df$snp_2 <- as.integer(df$snp_2)
#  df$chr <- as.integer(df$chr)
  return(df)
})
names(data_list) <- as.integer(data_files_trunc)

# reorder
data_list <- data_list[order(as.integer(names(data_list)))]

Get distance measure

data_list <- lapply(data_list, function(chr){
  chr$distance_kb <- abs(chr$snp_1 - chr$snp_2) / 1000
#  chr$chr <- as.integer(chr$chr)
  return(chr)
})

Collapse into single DF

data_df <- dplyr::bind_rows(data_list)

Plot by chr

# TEST
test_df <- dplyr::sample_n(data_df, 10000)

test_df %>% 
  ggplot(aes(distance_kb, r2)) +
  geom_point(size = 0.1, alpha = 0.005) +
  geom_smooth(size = 0.5) +
  theme_bw() +
  facet_wrap(~chr, nrow = 6, ncol = 4) +
  xlab("Distance between SNPs (kb)") +
  ylab(parse(text = "r^2"))

NA
NA
# TRUE
data_df %>% 
  ggplot(aes(distance_kb, r2)) +
  geom_point(size = 0.1, alpha = 0.005) +
  geom_smooth(size = 0.5) +
  theme_bw() +
  facet_wrap(~chr, nrow = 6, ncol = 4) +
  xlab("Distance between SNPs (kb)") +
  ylab(parse(text = "r^2"))

ggsave(filename = paste("20200715_ld_decay_subset_allchr_min-maf-0.10_max-maf-0.90", ".png", sep = ""),
       device = "png",
       path = "~/Documents/Docs/medaka\ pics/20200602_mikk_genome/",
       width = 15,
       height = 15,
       units = "cm",
       dpi = 500)

Get MAF stats

Create VCF with MAF

# No missing
bcftools +fill-tags \
  vcfs/panel_no-sibs_line-ids_no-missing.vcf.gz \
  --output-type z \
  --output vcfs/panel_no-sibs_line-ids_no-missing_with-maf.vcf.gz \
  -- \
  --tags MAF
## Count of variants: 20,086,433  
# No missing, biallelic SNPs only
bcftools view \
  --min-alleles 2 \
  --max-alleles 2\
  --types snps \
  --output-type z \
  --output vcfs/panel_no-sibs_line-ids_no-missing_with-maf_bi-snps.vcf.gz \
  vcfs/panel_no-sibs_line-ids_no-missing_with-maf.vcf.gz
## Count of variants: 16,035,052

Extract relevant fields

# make directory
mkdir maf
# get stats
bcftools query \
  --format '%CHROM\t%POS\t%INFO/MAF\n' \
  --output maf/20200707_maf.txt \
  vcfs/panel_no-sibs_line-ids_no-missing_with-maf_bi-snps.vcf.gz
  
# send to local
scp brettell@ebi:/hps/research1/birney/users/ian/mikk_paper/maf/20200707_maf.txt ~/Documents/Data/20200707_mikk_ld

Import to R

maf_dat <- read.table("~/Documents/Data/20200707_mikk_ld/20200707_maf.txt", 
                  header = F, sep = "\t")
colnames(maf_dat) <- c("chr", "pos", "maf")

Plot

maf_dat %>% 
  ggplot() +
  geom_histogram(aes(x = maf,
                     y=..count../1000000),
                 bins = 40,
                 fill = "#2A9D8F",
                 colour = "#264653") +
  theme_bw() +
  guides(fill = F) +
  xlab("Minor allele frequencies") +
  ylab("Count (in millions of sites)") 

ggsave(filename = paste("20200707_maf_freqs", ".png", sep = ""),
       device = "png",
       path = "~/Documents/Docs/medaka\ pics/20200602_mikk_genome/",
       width = 20,
       height = 13,
       units = "cm",
       dpi = 500)

Visualise using Haploview

Try gaston package

Make new BED

mkdir plink/20200714_panel_no-sibs_line-ids_no-missing_maf-0.05
  
# make BED  
plink \
  --vcf vcfs/panel_no-sibs_line-ids_no-missing.vcf.gz \
  --maf 0.05 \
  --make-bed \
  --double-id \
  --snps-only \
  --biallelic-only \
  --chr 1-24 \
  --allow-extra-chr \
  --out plink/20200714_panel_no-sibs_line-ids_no-missing_maf-0.05/20200714_panel_no-sibs_line-ids_no-missing_maf-0.05
  
# recode for 012
plink \
  --bfile plink/20200714_panel_no-sibs_line-ids_no-missing_maf-0.05/20200714_panel_no-sibs_line-ids_no-missing_maf-0.05 \
  --recode A \
  --chr 1-24 \
  --allow-extra-chr \
  --out plink/20200714_panel_no-sibs_line-ids_no-missing_maf-0.05/20200714_panel_no-sibs_line-ids_no-missing_maf-0.05_recode-012
  
# recode for 012 transposed
plink \
  --bfile plink/20200714_panel_no-sibs_line-ids_no-missing_maf-0.05/20200714_panel_no-sibs_line-ids_no-missing_maf-0.05 \
  --recode A-transpose \
  --chr 1-24 \
  --allow-extra-chr \
  --out plink/20200714_panel_no-sibs_line-ids_no-missing_maf-0.05/20200714_panel_no-sibs_line-ids_no-missing_maf-0.05_recode-012  
  
# send to local
scp brettell@ebi:/hps/research1/birney/users/ian/mikk_paper/plink/20200714_panel_no-sibs_line-ids_no-missing_maf-0.05/20200714_panel_no-sibs_line-ids_no-missing_maf-0.05_recode-012.raw ~/Documents/Data/20200707_mikk_ld/20200714_plink

scp brettell@ebi:/hps/research1/birney/users/ian/mikk_paper/plink/20200714_panel_no-sibs_line-ids_no-missing_maf-0.05/20200714_panel_no-sibs_line-ids_no-missing_maf-0.05_recode-012.traw ~/Documents/Data/20200707_mikk_ld/20200714_plink

scp brettell@ebi:/hps/research1/birney/users/ian/mikk_paper/plink/20200714_panel_no-sibs_line-ids_no-missing_maf-0.05/20200714_panel_no-sibs_line-ids_no-missing_maf-0.05.bim ~/Documents/Data/20200707_mikk_ld/20200714_plink

scp brettell@ebi:/hps/research1/birney/users/ian/mikk_paper/plink/20200714_panel_no-sibs_line-ids_no-missing_maf-0.05/20200714_panel_no-sibs_line-ids_no-missing_maf-0.05.fam ~/Documents/Data/20200707_mikk_ld/20200714_plink

Read in data

library(gaston)
library(tidyverse)

mikk <- read.table("~/Documents/Data/20200707_mikk_ld/20200714_plink/20200714_panel_no-sibs_line-ids_no-missing_maf-0.05_recode-012.traw",
                   header = T)

# BIM
mikk.bim <- read.table("~/Documents/Data/20200707_mikk_ld/20200714_plink/20200714_panel_no-sibs_line-ids_no-missing_maf-0.05.bim",
                       header = F,
                       col.names = c("chr", "id", "dist", "pos", "A1", "A2"))

# FAM
mikk.fam <- read.table("~/Documents/Data/20200707_mikk_ld/20200714_plink/20200714_panel_no-sibs_line-ids_no-missing_maf-0.05.fam",
                       header = F,
                       col.names = c("famid", "id", "father", "mother", "sex", "pheno"))

Preprocessing

# rename sample IDs
mikk.gen <- mikk
colnames(mikk.gen)[7:ncol(mikk.gen)] <-  mikk.fam$id
# remove unneeded columns
mikk.gen <- mikk.gen[, c(1, 7:ncol(mikk.gen))]
# split by chromosome
mikk.gen_lst <- split(mikk.gen, f = mikk.gen$CHR)
# remove CHR column
mikk.gen_lst <- lapply(mikk.gen_lst, function(chr){
  chr$CHR <- NULL
  return(chr)
})

# split BIM by chr as well
## get counts
mikk.bim %>% group_by(chr) %>% count
## split by chr
mikk.bim_lst <- split(mikk.bim, f = mikk.bim$chr)

Test

set.seed(45)
targ_ind <- sort(sample(nrow(mikk.gen_lst$`8`), 1000))
# pull out 50 SNPs
mikk.gen_8 <- mikk.gen_lst$`8`[targ_ind, ]
mikk.gen_8 <- t(as.matrix(mikk.gen_8))
mikk.bim_8 <- mikk.bim_lst$`8`[targ_ind, ]
# create bed matrix
x <- as.bed.matrix(mikk.gen_8, bim = mikk.bim_8)
# compute LD
ld.x <- gaston::LD(x, c(1,ncol(x)))
# replace NaNs with 0
ld.x[which(is.na(ld.x))] <- 0
# plot
LD.plot( ld.x,
         snp.positions = x@snps$pos, 
         max.dist = 1000000,
         write.ld = NULL,
         write.snp.id = F,
         pdf.file = "~/Documents/Docs/medaka pics/20200602_mikk_genome/20200714_test.pdf")
null device 
          1 

WORKS!

Run on all chrs

# get vector of seeds 
set.seed(5)
seeds <- sample(seq(1, 100), 24)
# run over list
counter <- 0
lapply(mikk.gen_lst, function(chr){
  counter <<- counter + 1
  # get seed
  set.seed(seeds[counter])
  targ_ind <- sort(sample(nrow(mikk.gen_lst[[counter]]), 1000))
  # pull out 50 SNPs
  mikk.gen <- mikk.gen_lst[[counter]][targ_ind, ]
  mikk.gen <- t(as.matrix(mikk.gen))
  mikk.bim <- mikk.bim_lst[[counter]][targ_ind, ]
  # create bed matrix
  x <- as.bed.matrix(mikk.gen, bim = mikk.bim)
  # compute LD
  ld.x <- gaston::LD(x, c(1,ncol(x)))
  # replace NaNs with 0
  ld.x[which(is.na(ld.x))] <- 0
  # plot
  LD.plot(ld.x,
          snp.positions = x@snps$pos, 
          max.dist = 1000000,
          write.ld = NULL,
          write.snp.id = F,
          pdf.file = paste("~/Documents/Docs/medaka pics/20200602_mikk_genome/",
                           gsub("-", "", Sys.Date()),
                           "_chr",
                           counter,
                           ".pdf",
                           sep = ""))
})

Get BED matrix for each chr

set.seed(5)
seeds <- sample(seq(1, 100), 24)

counter <- 0
mikk_bed_lst <- lapply(mikk.gen_lst, function(chr){
  counter <<- counter + 1
  # turn chr into list
  chr <- list()
  
  # get bed matrix
  ## set up GEN and BIM files
  mikk.gen <- mikk.gen_lst[[counter]]
  mikk.gen <- t(as.matrix(mikk.gen))
  mikk.bim <- mikk.bim_lst[[counter]]
  ## form BED matrix
  x <- gaston::as.bed.matrix(mikk.gen, bim = mikk.bim)  
  chr[["bed_mat"]] <- x 

  # get LD matrix
  ## get seed
  set.seed(seeds[counter])
  targ_ind <- sort(sample(nrow(mikk.gen_lst[[counter]]), 1000))
  chr[["target_snps_indexes"]] <- targ_ind
  ## pull out select SNPs
  mikk.gen <- mikk.gen_lst[[counter]][targ_ind, ]
  mikk.gen <- t(as.matrix(mikk.gen))
  mikk.bim <- mikk.bim_lst[[counter]][targ_ind, ]
  # create bed matrix
  x <- as.bed.matrix(mikk.gen, bim = mikk.bim)
  # compute LD
  ld.x <- gaston::LD(x, c(1,ncol(x)))
  chr[["LD"]] <- ld.x
  return(chr)
#  # replace NaNs with 0
#  ld.x[which(is.na(ld.x))] <- 0
})

Pull out all SNPS

unique(all_snps$chr[which(all_snps$N2 == 63)])
[1] 24

Make MAF plot with just these

Plot

all_snps %>% 
  ggplot() +
  geom_histogram(aes(x = maf_manual,
                     y=..count../1000000),
                 bins = 40,
                 fill = "#f4a261",
                 colour = "#e76f51") +
  theme_bw() +
  guides(fill = F) +
  xlab("Minor allele frequencies") +
  ylab("Count (in millions of sites)") 

Pull out entries with LD of 1

TEST

# get data frame of matrix indices with R^2 of 1
test <- data.frame(which(mikk_bed_lst[["1"]][["LD"]] == 1, arr.ind = T))
# remove diagonals
test <- test[which(test$row != test$col), ]
# get indices in full snp list
snp_1_ind <- mikk_bed_lst[["1"]][["target_snps_indexes"]][test$row]
snp_2_ind <- mikk_bed_lst[["1"]][["target_snps_indexes"]][test$col]
# get distances between those snps
high_ld_df <- data.frame(snp_1_pos = mikk_bed_lst[["1"]]$bed_mat@snps$pos[snp_1_ind],
                         snp_2_pos = mikk_bed_lst[["1"]]$bed_mat@snps$pos[snp_2_ind],
                         snp_1_maf = mikk_bed_lst[["1"]]$bed_mat@snps$maf[snp_1_ind],
                         snp_2_maf = mikk_bed_lst[["1"]]$bed_mat@snps$maf[snp_2_ind])
high_ld_df$distance_kb <- abs((high_ld_df$snp_2_pos - high_ld_df$snp_1_pos)/1e6)

TRUE

high_ld_lst <- lapply(mikk_bed_lst, function(x){
  # get data frame of matrix indices with R^2 of 1
  test <- data.frame(which(x[["LD"]] > 0.9, arr.ind = T))  
  # remove diagonals
  test <- test[which(test$row != test$col), ]
  # get count
  x[["high_ld_count"]] <- test
  # get indices for full snp list
  snp_1_ind <- mikk_bed_lst[["1"]][["target_snps_indexes"]][test$row]
  snp_2_ind <- mikk_bed_lst[["1"]][["target_snps_indexes"]][test$col]  
  # get distances between those snps
  high_ld_df <- data.frame(snp_1_pos = mikk_bed_lst[["1"]]$bed_mat@snps$pos[snp_1_ind],
                           snp_2_pos = mikk_bed_lst[["1"]]$bed_mat@snps$pos[snp_2_ind],
                           snp_1_maf = mikk_bed_lst[["1"]]$bed_mat@snps$maf[snp_1_ind],
                           snp_2_maf = mikk_bed_lst[["1"]]$bed_mat@snps$maf[snp_2_ind])
  high_ld_df$distance_kb <- abs((high_ld_df$snp_2_pos - high_ld_df$snp_1_pos)/1e6)
  x[["high_ld_df"]] <- high_ld_df
  return(x)
})

Create DFs for LD decay

TEST
test <- data.frame(high_ld_lst$`17`$LD)
colnames(test) <- high_ld_lst$`17`$bed_mat@snps$pos[high_ld_lst$`17`$target_snps_indexes]
test$snp_1_pos <- high_ld_lst$`17`$bed_mat@snps$pos[high_ld_lst$`17`$target_snps_indexes]
test2 <- pivot_longer(test,
                      cols = -snp_1_pos,
                      names_to = "snp_2_pos",
                      values_to = "r2")
test2$snp_1_pos <- as.integer(test2$snp_1_pos)
test2$snp_2_pos <- as.integer(test2$snp_2_pos)
test2$distance_kb <- abs((test2$snp_1_pos - test2$snp_2_pos)/1000000)
# remove diagonals
test2 <- test2[test2$distance_kb != 0, ]
TRUE
counter <- 0
ld_df_lst <- lapply(high_ld_lst, function(x){
  counter <<- counter + 1
  test <- data.frame(x$LD)
  colnames(test) <- x$bed_mat@snps$pos[x$target_snps_indexes]
  test$snp_1_pos <- x$bed_mat@snps$pos[x$target_snps_indexes]
  test2 <- pivot_longer(test,
                        cols = -snp_1_pos,
                        names_to = "snp_2_pos",
                        values_to = "r2")
  test2$snp_1_pos <- as.integer(test2$snp_1_pos)
  test2$snp_2_pos <- as.integer(test2$snp_2_pos)
  test2$distance_kb <- abs((test2$snp_1_pos - test2$snp_2_pos)/1000)
  # remove diagonals
  test2 <- test2[test2$distance_kb != 0, ]  
  # get chr
  test2$chr <- factor(names(high_ld_lst)[counter], levels = seq(1, 24))
  # put in order
  test2 <- test2 %>% dplyr::select(chr, snp_1_pos, snp_2_pos, distance_kb, r2)
  # assign
  x[["r2_df"]] <- test2
  return(x)
})

Plot

# Extract into data frame
ld_df <- lapply(ld_df_lst, function(x){
  x <- x$r2_df
  return(x)
})
ld_df <- dplyr::bind_rows(ld_df)
# remove comparisons beyond 50kb
ld_df_50kb <- ld_df[ld_df$distance_kb < 50, ]

# Plot
ld_df_50kb %>% 
  ggplot(aes(distance_kb, r2)) +
  geom_point(size = 0.1, alpha = 0.5) +
  geom_smooth(size = 0.5) +
  theme_bw() +
  facet_wrap(~chr, nrow = 6, ncol = 4) +
  xlab("Distance between SNPs (kb)") +
  ylab(parse(text = "r^2"))

Do LD plots again, excluding MAF < 0.10

# get vector of seeds 
set.seed(5)
seeds <- sample(seq(1, 100), 24)
# run over list
counter <- 0
ld_plot_lst <- lapply(mikk.gen_lst, function(chr){
  chr <- list()
  counter <<- counter + 1
  
  # create BED MAT from full files
  mikk.gen <- mikk.gen_lst[[counter]]
  mikk.gen <- t(as.matrix(mikk.gen))
  mikk.bim <- mikk.bim_lst[[counter]]
  x <- as.bed.matrix(mikk.gen, bim = mikk.bim)
  chr[["bed_mat_full"]] <- x
  
  # get indexes to keep
  filt_ind <- which(x@snps$maf > 0.10)
  
  # filter from original files and make BED again
  mikk.gen_filt <- mikk.gen_lst[[counter]][filt_ind, ]
  mikk.gen_filt <- t(as.matrix(mikk.gen_filt))  
  mikk.bim_filt <- mikk.bim_lst[[counter]][filt_ind, ]
  x <- as.bed.matrix(mikk.gen_filt, bim = mikk.bim_filt)
  chr[["bed_mat_filt"]] <- x  
  
  # get seed
  set.seed(seeds[counter])
  # made GEN file again
  mikk.gen_filt <- mikk.gen_lst[[counter]][filt_ind, ]
  # get sample indices
  targ_ind <- sort(sample(nrow(mikk.gen_filt), 1000))
  # pull out sample SNPs
  mikk.gen_samp <- mikk.gen_filt[targ_ind, ]
  mikk.gen_samp <- t(as.matrix(mikk.gen_samp))
  mikk.bim_samp <- mikk.bim_filt[targ_ind, ]
  # create bed matrix
  x <- as.bed.matrix(mikk.gen_samp, bim = mikk.bim_samp)
  chr[["bed_mat_samp"]] <- x
  # compute LD
  ld.x <- gaston::LD(x, c(1,ncol(x)))
  # replace NaNs with 0
  ld.x[which(is.na(ld.x))] <- 0

  # plot
#  LD.plot(ld.x,
#          snp.positions = x@snps$pos, 
#          max.dist = 1000000,
#          write.ld = NULL,
#          write.snp.id = F,
#          pdf.file = paste("~/Documents/Docs/medaka pics/20200602_mikk_genome/20200715_ld_maf-0.10/",
#                           "20200715_chr",
#                           counter,
#                           ".pdf",
#                           sep = ""))
  return(chr)
})

Get mean R^2

Run script over full file

Script here: code/scripts/20200715_r2_decay_mean.R

mkdir ld/20200715_mean_r2

# TEST
Rscript --vanilla mikk_genome/code/scripts/20200715_r2_decay_mean.R \
  ld/20200707_panel_maf-0.10_window-50kb_no-missing_maf-max-0.90/18.geno.ld \
  ld/20200715_mean_r2
# WORKS  

# TRUE  
for i in $(find ld/20200707_panel_maf-0.10_window-50kb_no-missing_maf-max-0.90/*); do
  name=$(basename $i | cut -f1 -d".");
  bsub -M 50000 -n 4 -o log/20200715_$name\_mean-r2.out -e log/20200715_$name\_mean-r2.err "Rscript --vanilla mikk_genome/code/scripts/20200715_r2_decay_mean.R $i ld/20200715_mean_r2";
done

# Pull to local
scp -r brettell@ebi:/hps/research1/birney/users/ian/mikk_paper/ld/20200715_mean_r2/ ~/Documents/Data/20200707_mikk_ld/

Read in data

data_files <- list.files("~/Documents/Data/20200707_mikk_ld/20200715_mean_r2/")
There were 28 warnings (use warnings() to see them)

Plot

r2_df %>% ggplot() +
  geom_line(aes(bin_bdr, mean, colour = chr)) +
  theme_bw() +
  xlab("Distance beetween SNPs (bp)") +
  ylab(bquote(.("Mean r")^2)) +
  labs(colour = "Chromosome")

ggsave(filename = paste("20200715_mean-r2", ".png", sep = ""),
       device = "png",
       path = "~/Documents/Docs/medaka\ pics/20200602_mikk_genome/",
       width = 20,
       height = 13,
       units = "cm",
       dpi = 500)

Facet

r2_df %>% ggplot() +
  geom_line(aes(bin_bdr_kb, mean, colour = chr)) +
  theme_bw() +
  xlab("Distance beetween SNPs (Kb)") +
  ylab(bquote(.("Mean r")^2)) +
  facet_wrap(~chr, nrow = 6, ncol = 4) +
  guides(colour = F)

ggsave(filename = paste("20200715_mean-r2_facet", ".png", sep = ""),
       device = "png",
       path = "~/Documents/Docs/medaka\ pics/20200602_mikk_genome/",
       width = 20,
       height = 13,
       units = "cm",
       dpi = 500)

Do again, but with max distance of 1000 bp and 50 bins

mkdir ld/20200715_mean_r2_1kb-max
# TRUE  
for i in $(find ld/20200707_panel_maf-0.10_window-50kb_no-missing_maf-max-0.90/*); do
  name=$(basename $i | cut -f1 -d".");
  bsub -M 30000 -n 4 -o log/20200715_$name\_mean-r2_1kb-max.out -e log/20200715_$name\_mean-r2_1kb-max.err "Rscript --vanilla mikk_genome/code/scripts/20200715_r2_decay_mean_1kb-lim.R $i ld/20200715_mean_r2_1kb-max";
done

# Pull to local
scp -r brettell@ebi:/hps/research1/birney/users/ian/mikk_paper/ld/20200715_mean_r2_1kb-max/ ~/Documents/Data/20200707_mikk_ld/

Get heterozygosity stats

vcftools \
    --gzvcf vcfs/panel_no-sibs_line-ids.vcf.gz \
    --het \
    --out het/20200602

Read in data

data_files <- list.files("~/Documents/Data/20200707_mikk_ld/20200715_mean_r2_1kb-max/",
                         full.names = T)
data_files_trunc <- list.files("~/Documents/Data/20200707_mikk_ld/20200715_mean_r2_1kb-max/")
data_files_trunc <- gsub(".txt", "", data_files_trunc)

data_list <- lapply(data_files, function(data_file){
  df <- read.delim(data_file,
                   sep = "\t",
                   header = T)
  #names(df) <- c("chr", "snp_1", "snp_2", "count", "r2")
  return(df)
})
names(data_list) <- as.integer(data_files_trunc)

# reorder
data_list <- data_list[order(as.integer(names(data_list)))]

# bind into DF
r2_df <- dplyr::bind_rows(data_list, .id = "chr")
r2_df$chr <- factor(r2_df$chr, levels = seq(1, 24))

# get kb measure
r2_df$bin_bdr_kb <- r2_df$bin_bdr / 1000

Plot

r2_df %>% ggplot() +
  geom_line(aes(bin_bdr, mean, colour = chr)) +
  theme_bw() +
  xlab("Distance beetween SNPs (bp)") +
  ylab(bquote(.("Mean r")^2)) +
  labs(colour = "Chromosome")

ggsave(filename = paste("20200715_mean-r2_1kb-lim", ".png", sep = ""),
       device = "png",
       path = "~/Documents/Docs/medaka\ pics/20200602_mikk_genome/",
       width = 20,
       height = 13,
       units = "cm",
       dpi = 500)

No guides

r2_df %>% ggplot() +
  geom_line(aes(bin_bdr, mean, colour = chr)) +
  theme_bw() +
  xlab("Distance beetween SNPs (bp)") +
  ylab(bquote(.("Mean r")^2)) +
  guides(colour = F)

ggsave(filename = paste("20200715_mean-r2_1kb-lim_no-guide", ".png", sep = ""),
       device = "png",
       path = "~/Documents/Docs/medaka\ pics/20200602_mikk_genome/",
       width = 20,
       height = 13,
       units = "cm",
       dpi = 500)

Get counts of SNPs when MAF < 0.10

sum(unlist(lapply(ld_plot_lst, function(x) nrow(x[["bed_mat_filt"]]@snps))))
[1] 2938051

20200715 Birney Group meeting

Get human LD plot – contrast. Major one we want to make. And it’s not quite as good as Drosophila and accept that.

Tracking down these LD blocks. Investigate individually. Find explanation for one. Describe the reason why.

For these variants in the blocks, the samples will split be ancestry. As we raise the MAF, we hide the unbalanced scenarios. Take SNPs in blocks. Make a matrix. SNPs by samples, then cluster. Try Hclust. Hopefully we have some on one side of the tree, some on the other. Tree won’t look balanced, but hopefully we have a sample on each side.

The other thing they could be is introgression from Northern medaka line. Came in and refuses to recombine with Southern medaka.

Could be regions of persistent heterozygosity? Sample regions of persistent heterozygosity and make bandage plots for them.

Let Felix know that it’s working out.

ABBA BABA

Get Stickleback data

Download to cluster

wget ftp://ftp.ensembl.org/pub/release-100/fasta/gasterosteus_aculeatus/dna/Gasterosteus_aculeatus.BROADS1.dna.toplevel.fa.gz

Clone repo

# On local
cd ~/Documents/Repositories  
git clone https://github.com/simonhmartin/genomics_general
LS0tCnRpdGxlOiAiTUlLSyBQYW5lbCBnZW5vbWUgYW5hbHlzaXMgd29ya2Jvb2siCm91dHB1dDogaHRtbF9ub3RlYm9vawplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQotLS0KCiMgUGxhbgoKKjIwMjAwMjAzKgoKRnJvbSBtZWV0aW5nIHdpdGggVG9tIEZpdHpnZXJhbGQgb24gMjYgTm92ZW1iZXIgMjAxOToKCuKAoiBJbnRyb2dyZXNzaW9uOgogIC0gQ3JlYXRlIGdpYW50IHBvcHVsYXRpb24gVkNGIC0gY2hvb3NlIHRoZSBkYXRhc2V0cy4gSnVzdCBhIGNhc2Ugb2YgbWVyZ2luZyBzb21lIFZDRnMuCiAgICAtIEdldCBzb21lIEluZG9uZXNpYW4gbWVkYWthCuKAoiBMRCBkZWNheToKICAtIExEIHBsb3RzIC0gcGVyIGNocm9tb3NvbWUuCiAgLSBIZWF0bWFwIHBlciBjaHJvbW9zb21lPwrigKIgRnN0IHBsb3QgIAoKIyBTZXR1cAoKIyMgQ3JlYXRlIGRpcmVjdG9yeSBzdHJ1Y3R1cmUgYW5kIGNsb25lIHJlcG8KCldvcmtpbmcgZGlyZWN0b3J5IGhlcmU6IGAvaHBzL3Jlc2VhcmNoMS9iaXJuZXkvdXNlcnMvaWFuL21pa2tfcGFwZXJgCgpgYGB7YmFzaH0KIyBtb3ZlIHRvIHdvcmtpbmcgZGlyZWN0b3J5CmhvbWVocHMKY2QgbWlra19wYXBlcgojIGNsb25lIGdpdCByZXBvc2l0b3J5CmdpdCBjbG9uZSBodHRwczovL2dpdGh1Yi5jb20vSWFuLUJyZXR0ZWxsL21pa2tfZ2Vub21lLmdpdAojIGNyZWF0ZSBkaXJlY3RvcnkgZm9yIFZDRnMKbWtkaXIgdmNmcwpgYGAKCiMjIFB1bGwgYWNyb3NzIE1JS0sgUGFuZWwgVkNGCgpgYGB7cn0KY3AgL25mcy9yZXNlYXJjaDEvYmlybmV5L3Byb2plY3RzL21lZGFrYS9pbmJyZWRfcGFuZWwvbWVkYWthLWFsaWdubWVudHMtcmVsZWFzZS05NC92Y2YvbWVkYWthX2luYnJlZF9wYW5lbF9lbnNlbWJsX25ld19yZWZlcmVuY2VfcmVsZWFzZV85NC52Y2YqIHZjZnMKYGBgCgojIyBLZXkgZmlsZSBmb3IgY3JhbSBJRCB0byBsaW5lIElECgpgbWlra19nZW5vbWUvZGF0YS8yMDIwMDIwNl9jcmFtX2lkX3RvX2xpbmVfaWQudHh0YAoKIyMgUmVtb3ZlIGR1cGxpY2F0ZXMgYW5kIG5vbi1wYW5lbCBsaW5lcwoKYGBge2Jhc2h9CiMgRmluZCBkdXBsaWNhdGVzCnNzaCBlYmkKaG9tZWhwcwpjZCBtaWtrX3BhcGVyL21pa2tfZ2Vub21lLwpjYXQgZGF0YS8yMDIwMDIwNl9jcmFtX2lkX3RvX2xpbmVfaWQudHh0IHwgY3V0IC1mMiB8IGN1dCAtZjEgLWQiXyIgfCBzb3J0IHwgdW5pcSAtZApgYGAKCk5vdGUgdGhlIGZvbGxvd2luZyBkdXBsaWNhdGVzOgoKLTEwNgotMTEKLTExNwotMTMxCi0xMzIKLTEzNAotMTM1Ci0xMzgKLTE0Ci0xNDAKLTE0MQotMTUKLTIzCi0zMgotMzkKLTQKLTQwCi00OQotNTkKLTY5Ci03Ci03MQotNzIKLTgwCi04NAoKT25seSB0YWtlIF8xIHNpYmxpbmcgZnJvbSBwYWlyLCB1bmxlc3Mgd2hhdCBpcyBleGNsdWRlZCBpcyB0aGUgb25seSBzdXJ2aXZvciBiYXNlZCBvbiBgbWlra19iZWhhdmlvdXIvZGF0YS9wYW5lbF8xLzIwMjAwMTA5X3BhbmVsX2xpbmVzLnR4dGAuCgoqUXVlcnkqIHdoZXRoZXIgd2Uga2VlcCB0aGUgbGluZXMgdGhhdCBtYXkgaGF2ZSBkaWVkIG91dD8gQXNrIEZlbGl4LgoKIyMgS2V5IGZpbGUgZm9yIG5vIHNpYnMKCmBtaWtrX2dlbm9tZS9kYXRhLzIwMjAwMjA2X2NyYW0ybGluZV9rZXlfbm8tc2licy50eHRgCgpFeGNsdWRlZCBJRHM6IGBtaWtrX2dlbm9tZS9kYXRhLzIwMjAwMjA2X2V4Y2x1ZGVkX2xpbmVzLnR4dGAKCioyMDIwMDIyNSoKCkZ1bGwgbGlzdCBvZiBNSUtLIGxpbmVzIGZyb20gRmVsaXggaGVyZTogYG1pa2tfZ2Vub21lL2RhdGEvMjAyMDAyMTBfcGFuZWxfbGluZXNfZnVsbC50eHRgCgpgYGB7YmFzaH0KY2F0IH4vRG9jdW1lbnRzL1JlcG9zaXRvcmllcy9taWtrX2dlbm9tZS9kYXRhLzIwMjAwMjEwX3BhbmVsX2xpbmVzX2Z1bGwudHh0IGN1dCAtZjEgLWQiLSIgfCBzb3J0IHwgdW5pcSAtZApgYGAKCi0gMTA2Ci0gMTEKLSAxMTcKLSAxMzEKLSAxMzIKLSAxMzUKLSAxNAotIDE0MAotIDIzCi0gMzkKLSA0Ci0gNDAKLSA1OQotIDY5Ci0gNzIKLSA4MAoKTGlzdCB3aXRoIG5vIHNpYmxpbmcgbGluZXMgaGVyZTogYG1pa2tfZ2Vub21lL2RhdGEvMjAyMDAyMjdfcGFuZWxfbGluZXNfbm8tc2licy50eHRgLiA2NCBsaW5lcyB0b3RhbC4KCkV4Y2x1ZGVkIElEcyBoZXJlOiBgbWlra19nZW5vbWUvZGF0YS8yMDIwMDIyN19wYW5lbF9saW5lc19leGNsdWRlZC50eHRgLiAxNiBsaW5lcyB0b3RhbC4KClJlcGxhY2UgYWxsIGRhc2hlcyB3aXRoIHVuZGVyc2NvcmVzIHRvIG1hdGNoIGNyYW0ybGluZSBrZXkgZmlsZQpgYGB7YmFzaH0Kc2VkICdzLy0vXy9nJyBkYXRhLzIwMjAwMjI3X3BhbmVsX2xpbmVzX25vLXNpYnMudHh0ID4gZGF0YS8yMDIwMDIyN19wYW5lbF9saW5lc19uby1zaWJzX3VzLnR4dCAgCmBgYAoKRXh0cmFjdCB0aGUgbGluZXMgdG8ga2VlcCBmcm9tIHRoZSBrZXkgZmlsZS4KYGBge2Jhc2h9CmF3ayAgJ0ZOUj09TlIge2YxWyQwXTsgbmV4dH0gJDIgaW4gZjEnIGRhdGEvMjAyMDAyMjdfcGFuZWxfbGluZXNfbm8tc2lic191cy50eHQgZGF0YS8yMDIwMDIwNl9jcmFtX2lkX3RvX2xpbmVfaWQudHh0ID4gZGF0YS8yMDIwMDIyN19jcmFtMmxpbmVfbm8tc2licy50eHQKYGBgCgpIYXMgNjYgbGluZXMgaW5zdGVhZCBvZiA2MyAoYmVjYXVzZSB3ZSdyZSBtaXNzaW5nIDEzMC0yKSwgc28gdGhlcmUgbXVzdCBiZSBkdXBsaWNhdGVzLiBGaW5kIG91dCB3aGljaCBvbmVzOgoKYGBge2Jhc2h9CmNhdCBkYXRhLzIwMjAwMjI3X2NyYW0ybGluZV9uby1zaWJzLnR4dCB8IGN1dCAtZjIgfCBjdXQgLWYxIC1kIl8iIHwgc29ydCB8IHVuaXEgLWQKYGBgCgozMgo3MQo4NAoKTWFudWFsbHkgcmVtb3ZlZCAoYGRhdGEvMjAyMDAyMjdfZHVwbGljYXRlc19leGNsdWRlZC50eHRgKToKCuKAoiAyNDI3MV83IzUJMzJfMgrigKIgMjQyNzFfOCM0CTcxXzEK4oCiIDI0MjU5XzEjMQk4NF8yCgpGaW5hbCB2ZXJzaW9uOiBgZGF0YS8yMDIwMDIyN19jcmFtMmxpbmVfbm8tc2licy50eHRgCgpGaW5hbCB2ZXJzaW9uLCBjcmFtIElEcyBvbmx5OgoKIyBDcmVhdGUgZmlsdGVyZWQgVkNGCgojIyBSZW5hbWUgc2FtcGxlcyB1c2luZyBCQ0ZUT09MUwoKYGBge2Jhc2h9CiMgY3JlYXRlIGxpc3Qgb2YgQ1JBTSBJRHMgaW4gVkNGCmJjZnRvb2xzIHF1ZXJ5IC1sIHZjZnMvbWVkYWthX2luYnJlZF9wYW5lbF9lbnNlbWJsX25ld19yZWZlcmVuY2VfcmVsZWFzZV85NC52Y2YgPiB0bXAudHh0CiMgY29uZmlybSB0aGF0IGl0J3MgaW4gdGhlIHNhbWUgb3JkZXIgYXMgdGhlIGNvbHVtbiBpbiB0aGUgbGluZSBJRHMgZmlsZQpjdXQgLWYxIG1pa2tfZ2Vub21lL2RhdGEvMjAyMDAyMDZfY3JhbV9pZF90b19saW5lX2lkLnR4dCB8IHRhaWwgLW4rMiA+IHRtcDIudHh0CiMgYmFzaCBzY3JpcHQgdG8gY29tcGFyZQpmaWxlMT0idG1wLnR4dCIKZmlsZTI9InRtcDIudHh0IgoKaWYgY21wIC1zICIkZmlsZTEiICIkZmlsZTIiOyB0aGVuCiAgICBwcmludGYgJ1RoZSBmaWxlICIlcyIgaXMgdGhlIHNhbWUgYXMgIiVzIlxuJyAiJGZpbGUxIiAiJGZpbGUyIgplbHNlCiAgICBwcmludGYgJ1RoZSBmaWxlICIlcyIgaXMgZGlmZmVyZW50IGZyb20gIiVzIlxuJyAiJGZpbGUxIiAiJGZpbGUyIgpmaQojIGNsZWFuIHVwCnJtIHRtcCoKCiMgY3JlYXRlIGZpbGUgd2l0aCBubyBoZWFkZXIKdGFpbCAtbisyIG1pa2tfZ2Vub21lL2RhdGEvMjAyMDAyMDZfY3JhbV9pZF90b19saW5lX2lkLnR4dCA+IG1pa2tfZ2Vub21lL2RhdGEvMjAyMDAyMDNfY3JhbTJsaW5lX25vLWhlYWRlci50eHQKIyByZXBsYWNlIHRhYiB3aXRoIHNwYWNlCnNlZCAncy9cdC8gL2cnIG1pa2tfZ2Vub21lL2RhdGEvMjAyMDAyMDNfY3JhbTJsaW5lX25vLWhlYWRlci50eHQgPiB0bXAudHh0Cm12IHRtcC50eHQgbWlra19nZW5vbWUvZGF0YS8yMDIwMDIwM19jcmFtMmxpbmVfbm8taGVhZGVyLnR4dAoKIyBSZW5hbWUgc2FtcGxlcyB3aXRoIEJDRlRPT0xTCmJjZnRvb2xzIHJlaGVhZGVyIC0tb3V0cHV0LWZpbGUgdmNmcy9wYW5lbF9saW5lLWlkcy52Y2YgLS1zYW1wbGVzIG1pa2tfZ2Vub21lL2RhdGEvMjAyMDAyMDNfY3JhbTJsaW5lX25vLWhlYWRlci50eHQgdmNmcy9tZWRha2FfaW5icmVkX3BhbmVsX2Vuc2VtYmxfbmV3X3JlZmVyZW5jZV9yZWxlYXNlXzk0LnZjZgojIHRlc3QKYmNmdG9vbHMgcXVlcnkgLWwgIHZjZnMvcGFuZWxfbGluZS1pZHMudmNmCiNbRTo6YmNmX2hkcl9hZGRfc2FtcGxlXSBEdXBsaWNhdGVkIHNhbXBsZSBuYW1lICc4NF8yJwojW0U6OmJjZl9oZHJfYWRkX3NhbXBsZV0gRHVwbGljYXRlZCBzYW1wbGUgbmFtZSAnMTQxXzMnCiNbRTo6YmNmX2hkcl9hZGRfc2FtcGxlXSBEdXBsaWNhdGVkIHNhbXBsZSBuYW1lICczMl8yJwojW0U6OmJjZl9oZHJfYWRkX3NhbXBsZV0gRHVwbGljYXRlZCBzYW1wbGUgbmFtZSAnNzFfMScKI0ZhaWxlZCB0byBvcGVuIHZjZnMvcGFuZWxfbGluZS1pZHMudmNmOiBjb3VsZCBub3QgcGFyc2UgaGVhZGVyCgojIGNyZWF0ZSBuby1zaWJzIGZpbGUgd2l0aCBDUkFNIElEIG9ubHkKY3V0IC1mMSBtaWtrX2dlbm9tZS9kYXRhLzIwMjAwMjI3X2NyYW0ybGluZV9uby1zaWJzLnR4dCA+IG1pa2tfZ2Vub21lL2RhdGEvMjAyMDAyMjdfY3JhbTJsaW5lX25vLXNpYnNfY3JhbS1vbmx5LnR4dAojIHB1bGwgb3V0IG9ubHkgc2FtcGxlcyB0byBiZSBpbmNsdWRlZCwgdGhlbiByZWNvZGUKYmNmdG9vbHMgdmlldyAtLW91dHB1dC1maWxlIHZjZnMvcGFuZWxfbm8tc2licy52Y2YgLS1zYW1wbGVzLWZpbGUgbWlra19nZW5vbWUvZGF0YS8yMDIwMDIyN19jcmFtMmxpbmVfbm8tc2lic19jcmFtLW9ubHkudHh0IHZjZnMvbWVkYWthX2luYnJlZF9wYW5lbF9lbnNlbWJsX25ld19yZWZlcmVuY2VfcmVsZWFzZV85NC52Y2YKIyBTVUNDRVNTCiMgcmVjb2RlCmJjZnRvb2xzIHJlaGVhZGVyIC0tb3V0cHV0IHZjZnMvcGFuZWxfbm8tc2lic19saW5lLWlkcy52Y2YgLS1zYW1wbGVzIG1pa2tfZ2Vub21lL2RhdGEvMjAyMDAyMjdfY3JhbTJsaW5lX25vLXNpYnMudHh0IHZjZnMvcGFuZWxfbm8tc2licy52Y2YKIyBjb21wcmVzcwojIyBvcHRpb24gMTogYmd6aXAgdmNmcy9wYW5lbF9uby1zaWJzX2xpbmUtaWRzLnZjZgojIyBvcHRpb24gMjoKYmNmdG9vbHMgdmlldyAtLW91dHB1dC10eXBlIHogLS1vdXRwdXQtZmlsZSB2Y2ZzL3BhbmVsX25vLXNpYnNfbGluZS1pZHMudmNmLmd6IHZjZnMvcGFuZWxfbm8tc2lic19saW5lLWlkcy52Y2YKIyBjcmVhdGUgaW5kZXgKYmNmdG9vbHMgaW5kZXggLS10YmkgdmNmcy9wYW5lbF9uby1zaWJzX2xpbmUtaWRzLnZjZi5negpgYGAKCiMjIEdldCBzdGF0cyBvbiBuby1zaWJzIFZDRgoKYGBge2Jhc2h9Cm1rZGlyIHN0YXRzCmJjZnRvb2xzIHN0YXRzIHZjZnMvcGFuZWxfbm8tc2lic19saW5lLWlkcy52Y2YuZ3ogPiBzdGF0cy8yMDIwMDMwNV9wYW5lbF9uby1zaWJzLnR4dApgYGAKCuKAoiBudW1iZXIgb2Ygc2FtcGxlczogICAgICA2MwrigKIgbnVtYmVyIG9mIHJlY29yZHM6ICAgICAgKioyOSwxNjEsMDI0KioK4oCiIG51bWJlciBvZiBuby1BTFRzOiAgICAgIDAK4oCiIG51bWJlciBvZiBTTlBzOiAgICAgICAgICoqMjQsMDMxLDY3MyoqCuKAoiBudW1iZXIgb2YgTU5QczogICAgICAgICAwCuKAoiBudW1iZXIgb2YgaW5kZWxzOiAgICAgICA1NTc1OTk0CuKAoiBudW1iZXIgb2Ygb3RoZXJzOiAgICAgICA0NDkxNTkK4oCiIG51bWJlciBvZiBtdWx0aWFsbGVsaWMgc2l0ZXM6ICAgKjI5NTczNjYqCuKAoiBudW1iZXIgb2YgbXVsdGlhbGxlbGljIFNOUCBzaXRlczogICAgICAgMTQzNDkwOAoK4oCiIHRzOiAxMjY0MDQ3MArigKIgdHY6IDExODg2NDg0ICAK4oCiIHRzL3R2OiAxLjA2IAoKIyMgU3BsaXQgYnkgY2hyb21vc29tZQoKIyMjIEdldCByZWZlcmVuY2UKCmBgYHtiYXNofQpta2RpciByZWZzCgpjcCAvbmZzL3Jlc2VhcmNoMS9iaXJuZXkvcHJvamVjdHMvbWVkYWthL2luYnJlZF9wYW5lbC9tZWRha2EtYWxpZ25tZW50cy1yZWxlYXNlLTk0L3JlZi9Pcnl6aWFzX2xhdGlwZXMuQVNNMjIzNDY3djEqIHJlZnMvCmBgYAoKIyMjIFNwbGl0IGJ5IGNocm9tb3NvbWUKYGBge2Jhc2h9Cm1rZGlyIHZjZnMvc3BsaXRfYnlfY2hyCgpmb3IgaSBpbiAkKHNlcSAxIDI0KTsgZG8KICBic3ViIC1vIGxvZy9zcGxpdF9ieV9jaHJfJGkub3V0IC1lIGxvZy9zcGxpdF9ieV9jaHJfJGkuZXJyIFwKICAiYmNmdG9vbHMgZmlsdGVyIFwKICAgIC0tcmVnaW9ucyAkaSBcCiAgICAtLW91dHB1dC10eXBlIHogXAogICAgLS1vdXRwdXQgdmNmcy9zcGxpdF9ieV9jaHIvcGFuZWxfbm8tc2lic19jaHItJGkudmNmLmd6IFwKICAgIHZjZnMvcGFuZWxfbm8tc2lic19saW5lLWlkcy52Y2YuZ3oiOwpkb25lICAKYGBgCgojIyMgR2V0IHN0YXRzIHBlciBjaHJvbW9zb21lCgpgYGB7YmFzaH0KbWtkaXIgc3RhdHMvYnlfY2hyCgpmb3IgaSBpbiAkKHNlcSAxIDI0KTsgZG8KICBic3ViIC1vIGxvZy9zdGF0c19ieV9jaHJfJGkub3V0IC1lIGxvZy9zdGF0c19ieV9jaHJfJGkuZXJyIFwKICAiYmNmdG9vbHMgc3RhdHMgXAogICAgdmNmcy9zcGxpdF9ieV9jaHIvcGFuZWxfbm8tc2lic19jaHItJGkudmNmLmd6ID4gc3RhdHMvYnlfY2hyLyRpLnR4dCI7CmRvbmUgCmBgYAoKCgojIyBSdW4gTEQKCiMjIyBWQ0Z0b29scwoKYGBge2Jhc2h9Cm1rZGlyIGxkCm1rZGlyIGxkLzIwMjAwMzA1X3BhbmVsX21hZi0wLjAzX3dpbmRvdy01MGtiCgpmb3IgaSBpbiAkKHNlcSAxIDI0KTsgZG8KICBic3ViIC1NIDMwMDAwIC1uIDggLW8gbG9nL2xkXyRpLm91dCAtZSBsb2cvbGRfJGkuZXJyIFwKICAidmNmdG9vbHMgXAogICAgLS1nenZjZiB2Y2ZzL3NwbGl0X2J5X2Noci9wYW5lbF9uby1zaWJzX2Noci0kaS52Y2YuZ3ogXAogICAgLS1nZW5vLXIyIFwKICAgIC0tbGQtd2luZG93LWJwIDUwMDAwIFwKICAgIC0tbWFmIDAuMDMgXAogICAgLS1vdXQgbGQvMjAyMDAzMDVfcGFuZWxfbWFmLTAuMDNfd2luZG93LTUwa2IvJGkiOwpkb25lICAKCiMgY3JlYXRlcyBodWdlIGZpbGVzICh+MTBHKS4gVGFrZSByYW5kb20gMU0gbGluZXMKIyMgY3JlYXRlIHNldCB1cCBkaXJlY3RvcnkKbWtkaXIgbGQvMjAyMDAzMDVfcGFuZWxfbWFmLTAuMDNfd2luZG93LTUwa2JfdGhpbm5lZAojIyAKZm9yIGkgaW4gJChzZXEgMSAyNCk7IGRvCiAgYnN1YiAtbyBsb2cvbGRfdHJpbV8kaS5vdXQgLWUgbG9nL2xkX3RyaW1fJGkuZXJyIFwKICAiaGVhZCAtMSA+IGxkLzIwMjAwMzA1X3BhbmVsX21hZi0wLjAzX3dpbmRvdy01MGtiX3RoaW5uZWQvJGlcXzFtLnR4dCAmJiBcCiAgc2h1ZiAtbiAxMDAwMDAwIGxkLzIwMjAwMzA1X3BhbmVsX21hZi0wLjAzX3dpbmRvdy01MGtiLyRpLmdlbm8ubGQgPj4gbGQvMjAyMDAzMDVfcGFuZWxfbWFmLTAuMDNfd2luZG93LTUwa2JfdGhpbm5lZC8kaVxfMW0udHh0IjsKZG9uZQoKaGVhZCAtMSA+IGxkLzIwMjAwMzA1X3BhbmVsX21hZi0wLjAzX3dpbmRvdy01MGtiX3RoaW5uZWQvMjRfMW0udHh0CnNodWYgLW4gMTAwMDAwMCBsZC8yMDIwMDMwNV9wYW5lbF9tYWYtMC4wM193aW5kb3ctNTBrYi8yNC5nZW5vLmxkID4+IGxkLzIwMjAwMzA1X3BhbmVsX21hZi0wLjAzX3dpbmRvdy01MGtiX3RoaW5uZWQvMjRfMW0udHh0CmBgYAoKIyMjIFBsaW5rCgpgYGB7YmFzaH0KI1RyeSB3aXRoIHBsaW5rIGFuZCAtLXRoaW4gYXJndW1lbnQKbWtkaXIgbGQvMjAyMDAzMDVfcGFuZWxfbWFmLTAuMDNfd2luZG93LTUwa2JfcGxpbmsKCi9uZnMvc29mdHdhcmUvYmlybmV5L3BsaW5rIFwKICAtLXZjZiB2Y2ZzL3NwbGl0X2J5X2Noci9wYW5lbF9uby1zaWJzX2Noci0yNC52Y2YuZ3ogXAogIC0tZG91YmxlLWlkIFwKICAtLXRoaW4gMC4wMjUgXAogIC0tc25wcy1vbmx5IFwKICAtLWdlbm8gMC4zIFwKICAtLXIyIFwKICAtLWxkLXdpbmRvdy1yMiAwIFwKICAtLWxkLXdpbmRvdyA5OTk5OTkgXAogIC0tbGQtd2luZG93LWtiIDUwMDAwIFwKICAtLWNoci1zZXQgMjQgXAogIC0tb3V0IGxkLzIwMjAwMzA1X3BhbmVsX21hZi0wLjAzX3dpbmRvdy01MGtiX3BsaW5rL3Rlc3QKIyB3b3JrcwoKIyBUUlVFCmZvciBpIGluICQoc2VxIDI0IDI0KTsgZG8KICBic3ViIC1NIDMwMDAwIC1vIGxvZy9sZF9wbGlua18kaS5vdXQgLWUgbG9nL2xkX3BsaW5rXyRpLmVyciBcCiAgIi9uZnMvc29mdHdhcmUvYmlybmV5L3BsaW5rIFwKICAgIC0tdmNmIHZjZnMvc3BsaXRfYnlfY2hyL3BhbmVsX25vLXNpYnNfY2hyLSRpLnZjZi5neiBcCiAgICAtLWRvdWJsZS1pZCBcCiAgICAtLXRoaW4gMC4wMjUgXAogICAgLS1zbnBzLW9ubHkgXAogICAgLS1nZW5vIDAuMyBcCiAgICAtLXIyIFwKICAgIC0tbGQtd2luZG93LXIyIDAgXAogICAgLS1sZC13aW5kb3cgOTk5OTk5IFwKICAgIC0tbGQtd2luZG93LWtiIDUwMDAwIFwKICAgIC0tY2hyLXNldCAyNCBcCiAgICAtLW91dCBsZC8yMDIwMDMwNV9wYW5lbF9tYWYtMC4wM193aW5kb3ctNTBrYl9wbGluay8kaSI7CmRvbmUgIApgYGAKCi0tZG91YmxlLWlkIHJlbW92ZXMgdGhlIGlzc3VlIG9mIHRoZSBsaW5lIElEcyBoYXZpbmcgdW5kZXJzY29yZXMgaW4gdGhlbS4gCi0tdGhpbiAwLjAyNSB0YWtlcyBvbmx5IDAuMDI1IG9mIHRoZSB2YXJpYW50cwotLXNucHMtb25seSB0YWtlcyBvbmx5IFNOUHMKLS1nZW5vIDAuMyBmaWx0ZXJzIG91dCB2YXJpYW50cyB3aXRoIG1pc3NpbmcgY2FsbCByYXRlcyBhYm92ZSAwLjMKLS1yMiBnZXRzIHRoZSBSXjIKLS1sZC13aW5kb3ctcjIgMCBpbmNsdWRlcyBhbGwgcGFpcnMgb2YgdmFyaWFudHMsIGluY2x1ZGluZyB0aG9zZSB3aXRoIFJeMiBsZXNzIHRoYW4gMC4yCi0tbGQtd2luZG93IDk5OTk5OSBzZXRzIHRoZSBtYXhpbXVtIG51bWJlciBvZiB2YXJpYW50cyBhbGxvd2VkIGJldHdlZW4gYSBwYWlyIG9mIHZhcmlhbnRzCi0tbGQtd2luZG93LWtiIDUwMDAwIHNldHMgdGhlIGRpc3RhbmNlIG9mIHRoZSBjb21wYXJpc29uIHdpbmRvdwotLWNoci1zZXQgMjQgdGVsbHMgcGxpbmsgdGhhdCB0aGUgY2hyb21vc29tZSBudW1iZXIgaXMgMjQgc28gdGhhdCBpdCBkb2Vzbid0IGdldCBjb25mdXNlZCB0aGF0IHRoZXkncmUgbm90IGh1bWFuLgoKIyMgRmluZCBtaXNzaW5nIHNpdGVzCgpgYGB7YmFzaH0KZm9yIGkgaW4gJChzZXEgMSAyNCk7IGRvCiAgYnN1YiAtTSAyMDAwMCAtbiA0IC1vIGxvZy9taXNzaW5nXyRpLm91dCAtZSBsb2cvbWlzc2luZ18kaS5lcnIgXAogICJ2Y2Z0b29scyBcCiAgICAtLWd6dmNmIHZjZnMvc3BsaXRfYnlfY2hyL3BhbmVsX25vLXNpYnNfY2hyLSRpLnZjZi5neiBcCiAgICAtLW1pc3Npbmctc2l0ZSBcCiAgICAtLW91dCBtaXNzaW5nLyRpIjsKZG9uZQpgYGAKCiMjIFJlbmFtZSBmdWxsIHJ1bgoKIyMjIENyZWF0ZSBuZXcgY3JhbTJsaW5laWQgZmlsZSB3aXRoIGR1cGxpY2F0ZXMgZWRpdGVkCgpgYGB7YmFzaH0KIyBGaW5kIGR1cGxpY2F0ZXMKY3V0IC1mMiBtaWtrX2dlbm9tZS9kYXRhLzIwMjAwMjA2X2NyYW1faWRfdG9fbGluZV9pZC50eHQgfCBzb3J0IHwgdW5pcSAtY2QKYGBgCgrigKIgMiAxNDFfMwrigKIgMiAzMl8yCuKAoiAyIDcxXzEK4oCiIDIgODRfMgoKRWRpdGVkIHRoZW0gYXMgZm9sbG93czoKCuKAoiAyIDE0MV8zLTIK4oCiIDIgMzJfMi0yCuKAoiAyIDcxXzEtMgrigKIgMiA4NF8yLTIKClNhdmVkIGhlcmU6IGBtaWtrX2dlbm9tZS9kYXRhLzIwMjAwMzA1X2NyYW0ybGluZV9mdWxsX2R1cGVzLWVkaXRlZC50eHRgCgojIyMgUmVuYW1lIGZ1bGwgVkNGCgpgYGB7YmFzaH0KIyByZWhlYWQKYmNmdG9vbHMgcmVoZWFkZXIgXAogIC0tb3V0cHV0IHZjZnMvZnVsbC1ydW5fbGluZS1pZHMudmNmIFwKICAtLXNhbXBsZXMgbWlra19nZW5vbWUvZGF0YS8yMDIwMDMwNV9jcmFtMmxpbmVfZnVsbF9kdXBlcy1lZGl0ZWQudHh0IFwKICB2Y2ZzL21lZGFrYV9pbmJyZWRfcGFuZWxfZW5zZW1ibF9uZXdfcmVmZXJlbmNlX3JlbGVhc2VfOTQudmNmCiAgCiMgY29tcHJlc3MKYmNmdG9vbHMgdmlldyBcCiAgLS1vdXRwdXQtdHlwZSB6IFwKICAtLW91dHB1dC1maWxlIHZjZnMvZnVsbC1ydW5fbGluZS1pZHMudmNmLmd6IFwKICB2Y2ZzL2Z1bGwtcnVuX2xpbmUtaWRzLnZjZgogIAojIGluZGV4CmJjZnRvb2xzIGluZGV4IFwKICAtLXRiaSB2Y2ZzL2Z1bGwtcnVuX2xpbmUtaWRzLnZjZi5negpgYGAKCioyMDIwMDYwMioKCiMgR2V0IExEIHBsb3RzIHVzaW5nIFIuCgojIyBJbXBvcnQgZGF0YQoKYGBge3J9CmRhdGFfZmlsZXMgPC0gbGlzdC5maWxlcygifi9Eb2N1bWVudHMvRGF0YS8yMDIwMDMwNV9wYW5lbF9tYWYtMC4wM193aW5kb3ctNTBrYl90aGlubmVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bGwubmFtZXMgPSBUKQpkYXRhX2ZpbGVzX3RydW5jIDwtIGxpc3QuZmlsZXMoIn4vRG9jdW1lbnRzL0RhdGEvMjAyMDAzMDVfcGFuZWxfbWFmLTAuMDNfd2luZG93LTUwa2JfdGhpbm5lZCIpCmRhdGFfZmlsZXNfdHJ1bmMgPC0gZ3N1YigiXzFtLnR4dCIsICIiLCBkYXRhX2ZpbGVzX3RydW5jKQoKZGF0YV9saXN0IDwtIGxhcHBseShkYXRhX2ZpbGVzLCBmdW5jdGlvbihkYXRhX2ZpbGUpewogIGRmIDwtIHJlYWQuZGVsaW0oZGF0YV9maWxlLAogICAgICAgICAgICAgICAgICAgc2VwID0gIlx0IiwKICAgICAgICAgICAgICAgICAgIGhlYWRlciA9IEYpCiAgbmFtZXMoZGYpIDwtIGMoImNociIsICJzbnBfMSIsICJzbnBfMiIsICJjb3VudCIsICJyMiIpCiAgcmV0dXJuKGRmKQp9KQpuYW1lcyhkYXRhX2xpc3QpIDwtIGFzLmludGVnZXIoZGF0YV9maWxlc190cnVuYykKCiMgcmVvcmRlcgpkYXRhX2xpc3QgPC0gZGF0YV9saXN0W29yZGVyKGFzLmludGVnZXIobmFtZXMoZGF0YV9saXN0KSkpXQpgYGAKCiMjIEdldCBkaXN0YW5jZSBtZWFzdXJlCgpgYGB7cn0KZGF0YV9saXN0IDwtIGxhcHBseShkYXRhX2xpc3QsIGZ1bmN0aW9uKGNocil7CiAgY2hyJGRpc3RhbmNlX2tiIDwtIGFicyhjaHIkc25wXzEgLSBjaHIkc25wXzIpIC8gMTAwMAogIHJldHVybihjaHIpCn0pCmBgYAoKIyMgQ29sbGFwc2UgaW50byBzaW5nbGUgREYKCmBgYHtyfQpkYXRhX2RmIDwtIGRwbHlyOjpiaW5kX3Jvd3MoZGF0YV9saXN0KQpgYGAKCiMjIFBsb3QgYnkgY2hyCgpgYGB7cn0KIyBURVNUCnRlc3RfZGYgPC0gZHBseXI6OnNhbXBsZV9uKGRhdGFfZGYsIDEwMDAwKQoKdGVzdF9kZiAlPiUgCiAgZ2dwbG90KGFlcyhkaXN0YW5jZV9rYiwgcjIpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMC4xLCBhbHBoYSA9IDAuMDA1KSArCiAgZ2VvbV9zbW9vdGgoc2l6ZSA9IDAuNSkgKwogIHRoZW1lX2J3KCkgKwogIGZhY2V0X3dyYXAofmNociwgbnJvdyA9IDYsIG5jb2wgPSA0KSArCiAgeGxhYigiRGlzdGFuY2UgYmV0d2VlbiBTTlBzIChrYikiKSArCiAgeWxhYihwYXJzZSh0ZXh0ID0gInJeMiIpKQoKCmBgYAoKYGBge3J9CiMgVFJVRQpkYXRhX2RmICU+JSAKICBnZ3Bsb3QoYWVzKGRpc3RhbmNlX2tiLCByMikpICsKICBnZW9tX3BvaW50KHNpemUgPSAwLjEsIGFscGhhID0gMC4wMDUpICsKICBnZW9tX3Ntb290aChzaXplID0gMC41KSArCiAgdGhlbWVfYncoKSArCiAgZmFjZXRfd3JhcCh+Y2hyLCBucm93ID0gNiwgbmNvbCA9IDQpICsKICB4bGFiKCJEaXN0YW5jZSBiZXR3ZWVuIFNOUHMgKGtiKSIpICsKICB5bGFiKHBhcnNlKHRleHQgPSAicl4yIikpCmBgYAoKYGBge3J9Cmdnc2F2ZShmaWxlbmFtZSA9IHBhc3RlKCIyMDIwMDYwMl9sZF9kZWNheV9zdWJzZXRfYWxsY2hyIiwgIi5wbmciLCBzZXAgPSAiIiksCiAgICAgICBkZXZpY2UgPSAicG5nIiwKICAgICAgIHBhdGggPSAifi9Eb2N1bWVudHMvRG9jcy9tZWRha2FcIHBpY3MvMjAyMDA2MDJfbWlra19nZW5vbWUvIiwKICAgICAgIHdpZHRoID0gMTUsCiAgICAgICBoZWlnaHQgPSAxNSwKICAgICAgIHVuaXRzID0gImNtIiwKICAgICAgIGRwaSA9IDUwMCkKYGBgCgoKIyMgRmluZCBvdXQgd2hhdCB0aGUgU05QcyBoYXZlIGluIGNvbW1vbiAKCmBgYHtyfQojIERpc3RyaWJ1dGlvbiBvZiBjb3VudHMgaW4gd2hvbGUgZGF0YXNldApoaXN0KGRhdGFfZGYkY291bnQpCmBgYApgYGB7cn0KIyBob3cgbWFueT8KbGVuZ3RoKHdoaWNoKGRhdGFfZGYkY291bnQgPT0gNjMpKQpgYGAKCiMgUGxvdCBqdXN0IHRob3NlCgpgYGB7cn0KIyBUUlVFCmRhdGFfZGYgJT4lIAogIGRwbHlyOjpmaWx0ZXIoY291bnQgPT0gNjMpICU+JSAKICBnZ3Bsb3QoYWVzKGRpc3RhbmNlX2tiLCByMikpICsKICBnZW9tX3BvaW50KHNpemUgPSAwLjEsIGFscGhhID0gMC4wMDUpICsKICBnZW9tX3Ntb290aChzaXplID0gMC41KSArCiAgdGhlbWVfYncoKSArCiAgZmFjZXRfd3JhcCh+Y2hyLCBucm93ID0gNiwgbmNvbCA9IDQpICsKICB4bGFiKCJEaXN0YW5jZSBiZXR3ZWVuIFNOUHMgKGtiKSIpICsKICB5bGFiKHBhcnNlKHRleHQgPSAicl4yIikpCmBgYAoKYGBge3J9Cmdnc2F2ZShmaWxlbmFtZSA9IHBhc3RlKCIyMDIwMDYwM19sZF9kZWNheV9zdWJzZXRfYWxsY2hyX2FsbHNtcGxzIiwgIi5wbmciLCBzZXAgPSAiIiksCiAgICAgICBkZXZpY2UgPSAicG5nIiwKICAgICAgIHBhdGggPSAifi9Eb2N1bWVudHMvRG9jcy9tZWRha2FcIHBpY3MvMjAyMDA2MDJfbWlra19nZW5vbWUvIiwKICAgICAgIHdpZHRoID0gMjAsCiAgICAgICBoZWlnaHQgPSAyMCwKICAgICAgIHVuaXRzID0gImNtIiwKICAgICAgIGRwaSA9IDUwMCkKYGBgCgojIyBUYWtlIGEgbG9vayBhdCB0aG9zZSB3aXRoIHJeMiBvZiAxIGdyZWF0ZXIgdGhhbiAyMGtiIGF3YXkKCmBgYHtyfQpmdWxsX2NhbGxfZGYgPC0gZGF0YV9kZiAlPiUgCiAgZHBseXI6OmZpbHRlcihjb3VudCA9PSA2MyAmIHIyID09IDEgJiBkaXN0YW5jZV9rYiA+IDIwKQpmdWxsX2NhbGxfZGZfY250IDwtIGZ1bGxfY2FsbF9kZiAlPiUgCiAgZHBseXI6OmNvdW50KGNocikKCiMgUGxvdApmdWxsX2NhbGxfZGZfY250ICU+JSAKICBnZ3Bsb3QoYWVzKGNociwgbiwgZmlsbCA9IGZhY3RvcihjaHIpKSkgKyAKICBnZW9tX2NvbCgpICsKICB0aGVtZV9idygpICsKICBndWlkZXMoZmlsbCA9IEYpCmBgYApgYGB7cn0KVmlldyhmdWxsX2NhbGxfZGYgJT4lIGRwbHlyOjpmaWx0ZXIoZGlzdGFuY2UgPiAyMCkpCmBgYAoKTG9va2luZyBhdCBpbmRpdmlkdWFsIFNOUHMgaW4gdGhlIFZDRiB1c2luZyBncmVwLCBtb3N0IG9mIHRoZW0gaGF2ZSBsb3cgTUFGcyAoMyA8IHggPCA1KS4gUnVuIExEIGNhbGNzIGFnYWluIHVzaW5nIHRocmVzaG9sZCBvZiA1JS4KCmBgYHtiYXNofQpta2RpciBsZC8yMDIwMDMwNV9wYW5lbF9tYWYtMC4wNV93aW5kb3ctNTBrYgoKZm9yIGkgaW4gJChzZXEgMSAyNCk7IGRvCiAgYnN1YiAtTSAzMDAwMCAtbiA4IC1vIGxvZy9sZF8kaS5vdXQgLWUgbG9nL2xkXyRpLmVyciBcCiAgInZjZnRvb2xzIFwKICAgIC0tZ3p2Y2YgdmNmcy9zcGxpdF9ieV9jaHIvcGFuZWxfbm8tc2lic19jaHItJGkudmNmLmd6IFwKICAgIC0tZ2Vuby1yMiBcCiAgICAtLWxkLXdpbmRvdy1icCA1MDAwMCBcCiAgICAtLW1hZiAwLjA1IFwKICAgIC0tb3V0IGxkLzIwMjAwMzA1X3BhbmVsX21hZi0wLjA1X3dpbmRvdy01MGtiLyRpIjsKZG9uZSAgCmBgYAoKIyMgRmlsdGVyIGZpbGVzIG9uIGNsdXN0ZXIgZm9yIG9ubHkgdGhvc2Ugd2l0aCBmdWxsIGNhbGxzCgpgYGB7YmFzaH0KbWtkaXIgbGQvMjAyMDAzMDVfcGFuZWxfbWFmLTAuMDNfd2luZG93LTUwa2JfZnVsbC1jYWxscwoKZm9yIGkgaW4gJChmaW5kIGxkLzIwMjAwMzA1X3BhbmVsX21hZi0wLjAzX3dpbmRvdy01MGtiLzIzLmdlbm8ubGQpOyBkbwogIG5hbWU9JChiYXNlbmFtZSAkaSB8IGN1dCAtZjEgLWQiLiIpOwogIGF3a19zdWJzY3JpcHQ9JChlY2hvICJhd2sgJ1wkNCA9PSA2MycgJGkgPj4gbGQvMjAyMDAzMDVfcGFuZWxfbWFmLTAuMDNfd2luZG93LTUwa2JfZnVsbC1jYWxscy8kbmFtZS50eHQiKTsKICBzY3JpcHQ9JChlY2hvICJoZWFkIC0xICRpID4gbGQvMjAyMDAzMDVfcGFuZWxfbWFmLTAuMDNfd2luZG93LTUwa2JfZnVsbC1jYWxscy8kbmFtZS50eHQ7ICRhd2tfc3Vic2NyaXB0Iik7CiAgYnN1YiAtTSAzMDAwMCAtbyBsb2cvbGRfZnVsbC1jYWxsc18kbmFtZS5vdXQgLWUgbG9nL2xkX2Z1bGwtY2FsbHNfJG5hbWUuZXJyICQocHJpbnRmICRzY3JpcHQpOwpkb25lCiMgQ2FuJ3QgZG8gaXQgbGlrZSB0aGlzIC0gaGFzIGEgcHJvYmxlbSB3aXRoIHRoZSBhd2sgc2NyaXB0LiBIYXZlIHRvIGRvIGl0IGluIG9uZSBqb2I6Cgpmb3IgaSBpbiAkKGZpbmQgbGQvMjAyMDAzMDVfcGFuZWxfbWFmLTAuMDNfd2luZG93LTUwa2IvKik7IGRvCiAgbmFtZT0kKGJhc2VuYW1lICRpIHwgY3V0IC1mMSAtZCIuIik7CiAgaGVhZCAtMSAkaSA+IGxkLzIwMjAwMzA1X3BhbmVsX21hZi0wLjAzX3dpbmRvdy01MGtiX2Z1bGwtY2FsbHMvJG5hbWUudHh0OwogIGF3ayAnJDQgPT0gNjMnICRpID4+IGxkLzIwMjAwMzA1X3BhbmVsX21hZi0wLjAzX3dpbmRvdy01MGtiX2Z1bGwtY2FsbHMvJG5hbWUudHh0CmRvbmUgIApgYGAKCiMjIFJ1biBSIHNjcmlwdCB0byBjcmVhdGUgcGxvdHMKClIgc2NyaXB0IGhlcmU6IGBtaWtrX2dlbm9tZS9jb2RlL3NjcmlwdHMvMjAyMDA2MDJfbGRfZGVjYXlfcGxvdC5SYAoKYGBge2Jhc2h9CmZvciBpIGluICQoZmluZCBsZC8yMDIwMDMwNV9wYW5lbF9tYWYtMC4wM193aW5kb3ctNTBrYl9mdWxsLWNhbGxzLyogfCBoZWFkIC0xKTsgZG8KICBkYXRlX3RvZGF5PSQoZGF0ZSArJyVZJW0lZCcpOwogIG5hbWU9JChiYXNlbmFtZSAkaSB8IGN1dCAtZjEgLWQiLiIpOwogIGJzdWIgLU0gNTAwMDAgLW8gbG9nLyRkYXRlX3RvZGF5XF8kbmFtZVxfcGxvdGxkLm91dCAtZSBsb2cvJGRhdGVfdG9kYXlcXyRuYW1lXF9wbG90bGQuZXJyICJSc2NyaXB0IC0tdmFuaWxsYSBtaWtrX2dlbm9tZS9jb2RlL3NjcmlwdHMvMjAyMDA2MDJfbGRfZGVjYXlfcGxvdC5SICRpIHBsb3RzLyAkZGF0ZV90b2RheSI7CmRvbmUKIyBDYW4ndCBoYW5kbGUgaXQgd2l0aCA1ME1CIG1lbW9yeQpgYGAKCiMjIyBUcnkgd2l0aCBuZXcgTUFGIDAuMDUgY2FsbHMKCmBgYHtiYXNofQpmb3IgaSBpbiAkKGZpbmQgbGQvMjAyMDAzMDVfcGFuZWxfbWFmLTAuMDVfd2luZG93LTUwa2JfZnVsbC1jYWxscy8qIHwgaGVhZCAtMSk7IGRvCiAgZGF0ZV90b2RheT0kKGRhdGUgKyclWSVtJWQnKTsKICBuYW1lPSQoYmFzZW5hbWUgJGkgfCBjdXQgLWYxIC1kIi4iKTsKICBic3ViIC1NIDUwMDAwIC1vIGxvZy8kZGF0ZV90b2RheVxfcGxvdGxkXyRuYW1lLm91dCAtZSBsb2cvJGRhdGVfdG9kYXlcX3Bsb3RsZF8kbmFtZS5lcnIgIlJzY3JpcHQgLS12YW5pbGxhIG1pa2tfZ2Vub21lL2NvZGUvc2NyaXB0cy8yMDIwMDYwMl9sZF9kZWNheV9wbG90LlIgJGkgcGxvdHMvICRkYXRlX3RvZGF5IjsKZG9uZQojIFNUSUxMIGhhcyB0aGUgbGluZSBhdCBSXjIgPT0gMSEhCmBgYAoKKjIwMjAwNzA3KgoKVHJ5IGFsbCBhZ2FpbiwgdGhpcyB0aW1lIHJlbW92aW5nIGluZGVscy4KCiMjIyMgU2V0dXAKCmBgYHtiYXNofQpta2RpciBsZC8yMDIwMDcwN19wYW5lbF9tYWYtMC4wNV93aW5kb3ctNTBrYgpgYGAKCgojIyMjIEdldCBMRCBzdGF0cyB1c2luZyBgVkNGVG9vbHNgCgpgYGB7YmFzaH0KZm9yIGkgaW4gJChmaW5kIHZjZnMvc3BsaXRfYnlfY2hyLyopOyBkbwogIGRhdGVfdG9kYXk9JChkYXRlICsnJVklbSVkJyk7CiAgY2hyPSQoYmFzZW5hbWUgJGkgfCBhd2sgLUYnLScgJ3twcmludCAkM30nIHwgc2VkICdzLy52Y2YuZ3ovLycpOwogIGJzdWIgLU0gMzAwMDAgLW8gbG9nLyRkYXRlX3RvZGF5XF9sZF8kY2hyLm91dCAtZSBsb2cvJGRhdGVfdG9kYXlcX2xkXyRjaHIuZXJyIFwKICAidmNmdG9vbHMgXAogICAgLS1nenZjZiAkaSBcCgkgIC0tbGQtd2luZG93LWJwIDUwMDAwIFwKCSAgLS1tYWYgMC4wNSBcCgkgIC0tbWF4LWFsbGVsZXMgMiBcCgkgIC0tbWluLWFsbGVsZXMgMiBcCgkgIC0tcmVtb3ZlLWluZGVscyBcCgkgIC0tZ2Vuby1yMiBcCgkgIC0tb3V0IGxkLzIwMjAwNzA3X3BhbmVsX21hZi0wLjA1X3dpbmRvdy01MGtiLyRjaHIiOwpkb25lCmBgYAoKIyMjIENyZWF0ZSBuZXcgVkNGIHdpdGggb25seSBzaXRlcyB0aGF0IGhhdmUgbm8gbWlzc2luZyBnZW5vdHlwZXMKCmBgYHtiYXNofQojIG5lZWRzIC0tcmVjb2RlIGZsYWchIQp2Y2Z0b29scyBcCiAgLS1nenZjZiB2Y2ZzL3BhbmVsX25vLXNpYnNfbGluZS1pZHMudmNmLmd6IFwKICAtLW1heC1taXNzaW5nIDEgXAogIC0tcmVjb2RlIFwKICAtLXN0ZG91dCA+IHZjZnMvcGFuZWxfbm8tc2lic19saW5lLWlkc19uby1taXNzaW5nLnZjZgojIyBjb21wcmVzcwpiY2Z0b29scyB2aWV3IC0tb3V0cHV0LXR5cGUgeiAtLW91dHB1dC1maWxlIHZjZnMvcGFuZWxfbm8tc2lic19saW5lLWlkc19uby1taXNzaW5nLnZjZi5neiB2Y2ZzL3BhbmVsX25vLXNpYnNfbGluZS1pZHNfbm8tbWlzc2luZy52Y2YKIyBjcmVhdGUgaW5kZXgKYmNmdG9vbHMgaW5kZXggLS10YmkgdmNmcy9wYW5lbF9uby1zaWJzX2xpbmUtaWRzX25vLW1pc3NpbmcudmNmLmd6CmBgYAoK4oCiIG51bWJlciBvZiBzYW1wbGVzOgkgICAgICAgICAgICAgIDYzCuKAoiBudW1iZXIgb2YgcmVjb3JkczoJICAgICAgICAgICAgICAqKjIwLDA4Niw0MzMqKgrigKIgbnVtYmVyIG9mIG5vLUFMVHM6CSAgICAgICAgICAgICAgMArigKIgbnVtYmVyIG9mIFNOUHM6CSAgICAgICAgICAgICAgICAgICoqMTYsOTU2LDQwNSoqCuKAoiBudW1iZXIgb2YgTU5QczoJICAgICAgICAgICAgICAgICAgMArigKIgbnVtYmVyIG9mIGluZGVsczoJICAgICAgICAgICAgICAgIDMzMjk2ODEK4oCiIG51bWJlciBvZiBvdGhlcnM6CSAgICAgICAgICAgICAgICAwCuKAoiBudW1iZXIgb2YgbXVsdGlhbGxlbGljIHNpdGVzOgkgICAgMTMzMzE4MgrigKIgbnVtYmVyIG9mIG11bHRpYWxsZWxpYyBTTlAgc2l0ZXM6CTI2MDc3MAoKIyMjIFJlcnVuIExEIHN0YXRzIHdpdGggbWF4IE1BRiBvZiA5OSAodG8gZXhjbHVkZSB2YXJpYW50cyB3aGVyZSB0aGUgd2hvbGUgcGFuZWwgaXMgMS8xIGZvciB0aGUgQUxUKQoKYGBge2Jhc2h9CiMgbWFrZSBkaXJlY3RvcnkKbWtkaXIgbGQvMjAyMDA3MDdfcGFuZWxfbWFmLTAuMDVfd2luZG93LTUwa2Jfbm8tbWlzc2luZ19tYWYtbWF4LTAuOTkvCiMgcnVuCmZvciBpIGluICQoc2VxIDEgMjQpOyBkbwogIGRhdGVfdG9kYXk9JChkYXRlICsnJVklbSVkJyk7CiAgYnN1YiAtTSAzMDAwMCAtbyBsb2cvJGRhdGVfdG9kYXlcX2xkX21hZi1tYXhfJGNoci5vdXQgLWUgbG9nLyRkYXRlX3RvZGF5XF9sZF9tYWYtbWF4XyRjaHIuZXJyIFwKICAidmNmdG9vbHMgXAogICAgLS1nenZjZiB2Y2ZzL3BhbmVsX25vLXNpYnNfbGluZS1pZHNfbm8tbWlzc2luZy52Y2YuZ3ogXAoJICAtLWxkLXdpbmRvdy1icCA1MDAwMCBcCgkgIC0tY2hyICRpIFwKCSAgLS1tYWYgMC4wNSBcCgkgIC0tbWF4LW1hZiAwLjk5IFwKCSAgLS1tYXgtYWxsZWxlcyAyIFwKCSAgLS1taW4tYWxsZWxlcyAyIFwKCSAgLS1yZW1vdmUtaW5kZWxzIFwKCSAgLS1nZW5vLXIyIFwKCSAgLS1vdXQgbGQvMjAyMDA3MDdfcGFuZWxfbWFmLTAuMDVfd2luZG93LTUwa2Jfbm8tbWlzc2luZ19tYWYtbWF4LTAuOTkvJGkiOwpkb25lCmBgYAoKIyMjIyBUaGluCgpgYGB7YmFzaH0KIyMgY3JlYXRlIHNldCB1cCBkaXJlY3RvcnkKbWtkaXIgbGQvMjAyMDA3MDdfcGFuZWxfbWFmLTAuMDVfd2luZG93LTUwa2Jfbm8tbWlzc2luZ19tYWYtbWF4LTAuOTlfdGhpbm5lZC8KIyMgRXh0cmFjdCByYW5kb20gMU0gcGFpcnMKZm9yIGkgaW4gJChzZXEgMSAyNCk7IGRvCiAgZGF0ZV90b2RheT0kKGRhdGUgKyclWSVtJWQnKTsKICBic3ViIC1vIGxvZy8kZGF0ZV90b2RheVxfbGRfdHJpbV8kaS5vdXQgLWUgbG9nLyRkYXRlX3RvZGF5XF9sZF90cmltXyRpLmVyciBcCiAgImhlYWQgLTEgbGQvMjAyMDA3MDdfcGFuZWxfbWFmLTAuMDVfd2luZG93LTUwa2Jfbm8tbWlzc2luZ19tYWYtbWF4LTAuOTkvJGkuZ2Vuby5sZCA+IGxkLzIwMjAwNzA3X3BhbmVsX21hZi0wLjA1X3dpbmRvdy01MGtiX25vLW1pc3NpbmdfbWFmLW1heC0wLjk5X3RoaW5uZWQvJGlcXzFtLnR4dCAmJiBcCiAgc2h1ZiAtbiAxMDAwMDAwIGxkLzIwMjAwNzA3X3BhbmVsX21hZi0wLjA1X3dpbmRvdy01MGtiX25vLW1pc3NpbmdfbWFmLW1heC0wLjk5LyRpLmdlbm8ubGQgPj4gbGQvMjAyMDA3MDdfcGFuZWxfbWFmLTAuMDVfd2luZG93LTUwa2Jfbm8tbWlzc2luZ19tYWYtbWF4LTAuOTlfdGhpbm5lZC8kaVxfMW0udHh0IjsKZG9uZQojIyBzZW5kIHRvIGxvY2FsCnNjcCAtciBicmV0dGVsbEBlYmk6L2hwcy9yZXNlYXJjaDEvYmlybmV5L3VzZXJzL2lhbi9taWtrX3BhcGVyL2xkLzIwMjAwNzA3X3BhbmVsX21hZi0wLjA1X3dpbmRvdy01MGtiX25vLW1pc3NpbmdfbWFmLW1heC0wLjk5X3RoaW5uZWQvIH4vRG9jdW1lbnRzL0RhdGEvMjAyMDA3MDdfbWlra19sZApgYGAKCiMjIEltcG9ydCBkYXRhCgpgYGB7cn0KZGF0YV9maWxlcyA8LSBsaXN0LmZpbGVzKCJ+L0RvY3VtZW50cy9EYXRhLzIwMjAwNzA3X21pa2tfbGQvMjAyMDA3MDdfcGFuZWxfbWFmLTAuMDVfd2luZG93LTUwa2Jfbm8tbWlzc2luZ19tYWYtbWF4LTAuOTlfdGhpbm5lZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICBmdWxsLm5hbWVzID0gVCkKZGF0YV9maWxlc190cnVuYyA8LSBsaXN0LmZpbGVzKCJ+L0RvY3VtZW50cy9EYXRhLzIwMjAwNzA3X21pa2tfbGQvMjAyMDA3MDdfcGFuZWxfbWFmLTAuMDVfd2luZG93LTUwa2Jfbm8tbWlzc2luZ19tYWYtbWF4LTAuOTlfdGhpbm5lZCIpCmRhdGFfZmlsZXNfdHJ1bmMgPC0gZ3N1YigiXzFtLnR4dCIsICIiLCBkYXRhX2ZpbGVzX3RydW5jKQoKZGF0YV9saXN0IDwtIGxhcHBseShkYXRhX2ZpbGVzLCBmdW5jdGlvbihkYXRhX2ZpbGUpewogIGRmIDwtIHJlYWQuZGVsaW0oZGF0YV9maWxlLAogICAgICAgICAgICAgICAgICAgc2VwID0gIlx0IiwKICAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFQpCiAgbmFtZXMoZGYpIDwtIGMoImNociIsICJzbnBfMSIsICJzbnBfMiIsICJjb3VudCIsICJyMiIpCiAgcmV0dXJuKGRmKQp9KQpuYW1lcyhkYXRhX2xpc3QpIDwtIGFzLmludGVnZXIoZGF0YV9maWxlc190cnVuYykKCiMgcmVvcmRlcgpkYXRhX2xpc3QgPC0gZGF0YV9saXN0W29yZGVyKGFzLmludGVnZXIobmFtZXMoZGF0YV9saXN0KSkpXQpgYGAKCiMjIEdldCBkaXN0YW5jZSBtZWFzdXJlCgpgYGB7cn0KZGF0YV9saXN0IDwtIGxhcHBseShkYXRhX2xpc3QsIGZ1bmN0aW9uKGNocil7CiAgY2hyJGRpc3RhbmNlX2tiIDwtIGFicyhjaHIkc25wXzEgLSBjaHIkc25wXzIpIC8gMTAwMAogIHJldHVybihjaHIpCn0pCmBgYAoKIyMgQ29sbGFwc2UgaW50byBzaW5nbGUgREYKCmBgYHtyfQpkYXRhX2RmIDwtIGRwbHlyOjpiaW5kX3Jvd3MoZGF0YV9saXN0KQpgYGAKCiMjIFBsb3QgYnkgY2hyCgpgYGB7cn0KIyBURVNUCnRlc3RfZGYgPC0gZHBseXI6OnNhbXBsZV9uKGRhdGFfZGYsIDEwMDAwKQoKdGVzdF9kZiAlPiUgCiAgZ2dwbG90KGFlcyhkaXN0YW5jZV9rYiwgcjIpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMC4xLCBhbHBoYSA9IDAuMDA1KSArCiAgZ2VvbV9zbW9vdGgoc2l6ZSA9IDAuNSkgKwogIHRoZW1lX2J3KCkgKwogIGZhY2V0X3dyYXAofmNociwgbnJvdyA9IDYsIG5jb2wgPSA0KSArCiAgeGxhYigiRGlzdGFuY2UgYmV0d2VlbiBTTlBzIChrYikiKSArCiAgeWxhYihwYXJzZSh0ZXh0ID0gInJeMiIpKQoKCmBgYAoKYGBge3J9CiMgVFJVRQpkYXRhX2RmICU+JSAKICBnZ3Bsb3QoYWVzKGRpc3RhbmNlX2tiLCByMikpICsKICBnZW9tX3BvaW50KHNpemUgPSAwLjEsIGFscGhhID0gMC4wMDUpICsKICBnZW9tX3Ntb290aChzaXplID0gMC41KSArCiAgdGhlbWVfYncoKSArCiAgZmFjZXRfd3JhcCh+Y2hyLCBucm93ID0gNiwgbmNvbCA9IDQpICsKICB4bGFiKCJEaXN0YW5jZSBiZXR3ZWVuIFNOUHMgKGtiKSIpICsKICB5bGFiKHBhcnNlKHRleHQgPSAicl4yIikpCmBgYAoKYGBge3J9Cmdnc2F2ZShmaWxlbmFtZSA9IHBhc3RlKCIyMDIwMDcwOF9sZF9kZWNheV9zdWJzZXRfYWxsY2hyX21heF9tYWZfMC45OSIsICIucG5nIiwgc2VwID0gIiIpLAogICAgICAgZGV2aWNlID0gInBuZyIsCiAgICAgICBwYXRoID0gIn4vRG9jdW1lbnRzL0RvY3MvbWVkYWthXCBwaWNzLzIwMjAwNjAyX21pa2tfZ2Vub21lLyIsCiAgICAgICB3aWR0aCA9IDE1LAogICAgICAgaGVpZ2h0ID0gMTUsCiAgICAgICB1bml0cyA9ICJjbSIsCiAgICAgICBkcGkgPSA1MDApCmBgYAoKTG9va3MgYmV0dGVyIC0gd2l0aCByZWR1Y2VkIGRlbnNpdHkgdXAgdGhlIHRvcCBmb3Igc29tZSBjaHJvbW9zb21lcyAtIGJ1dCBmb3Igb3RoZXJzIHRoZXJlIGFyZSBzdGlsbCBzdHJvbmcgbGluZXMgd2l0aCBhbiByXjIgb2YgMS4gCgpUcnkgc2V0dGluZyB0aGUgbWF4IE1BRiBhdCAwLjUuIAoKIyMjIFJlcnVuIExEIHN0YXRzIHdpdGggbWF4IE1BRiBvZiAwLjUgCgpgYGB7YmFzaH0KIyBtYWtlIGRpcmVjdG9yeQpta2RpciBsZC8yMDIwMDcwN19wYW5lbF9tYWYtMC4wNV93aW5kb3ctNTBrYl9uby1taXNzaW5nX21hZi1tYXgtMC41MC8KIyBydW4KZm9yIGkgaW4gJChzZXEgMSAyNCk7IGRvCiAgZGF0ZV90b2RheT0kKGRhdGUgKyclWSVtJWQnKTsKICBic3ViIC1NIDMwMDAwIC1vIGxvZy8kZGF0ZV90b2RheVxfbGRfbWFmLW1heF8kY2hyLm91dCAtZSBsb2cvJGRhdGVfdG9kYXlcX2xkX21hZi1tYXhfJGNoci5lcnIgXAogICJ2Y2Z0b29scyBcCiAgICAtLWd6dmNmIHZjZnMvcGFuZWxfbm8tc2lic19saW5lLWlkc19uby1taXNzaW5nLnZjZi5neiBcCgkgIC0tbGQtd2luZG93LWJwIDUwMDAwIFwKCSAgLS1jaHIgJGkgXAoJICAtLW1hZiAwLjA1IFwKCSAgLS1tYXgtbWFmIDAuNTAgXAoJICAtLW1heC1hbGxlbGVzIDIgXAoJICAtLW1pbi1hbGxlbGVzIDIgXAoJICAtLXJlbW92ZS1pbmRlbHMgXAoJICAtLWdlbm8tcjIgXAoJICAtLW91dCBsZC8yMDIwMDcwN19wYW5lbF9tYWYtMC4wNV93aW5kb3ctNTBrYl9uby1taXNzaW5nX21hZi1tYXgtMC41MC8kaSI7CmRvbmUKYGBgCgojIyMjIFRoaW4KCmBgYHtiYXNofQojIyBjcmVhdGUgc2V0IHVwIGRpcmVjdG9yeQpta2RpciBsZC8yMDIwMDcwN19wYW5lbF9tYWYtMC4wNV93aW5kb3ctNTBrYl9uby1taXNzaW5nX21hZi1tYXgtMC41MF90aGlubmVkLwojIyBFeHRyYWN0IHJhbmRvbSAxTSBwYWlycwpmb3IgaSBpbiAkKHNlcSAxIDI0KTsgZG8KICBkYXRlX3RvZGF5PSQoZGF0ZSArJyVZJW0lZCcpOwogIGJzdWIgLW8gbG9nLyRkYXRlX3RvZGF5XF9sZF90cmltXyRpLm91dCAtZSBsb2cvJGRhdGVfdG9kYXlcX2xkX3RyaW1fJGkuZXJyIFwKICAiaGVhZCAtMSBsZC8yMDIwMDcwN19wYW5lbF9tYWYtMC4wNV93aW5kb3ctNTBrYl9uby1taXNzaW5nX21hZi1tYXgtMC41MC8kaS5nZW5vLmxkID4gbGQvMjAyMDA3MDdfcGFuZWxfbWFmLTAuMDVfd2luZG93LTUwa2Jfbm8tbWlzc2luZ19tYWYtbWF4LTAuNTBfdGhpbm5lZC8kaVxfMW0udHh0ICYmIFwKICBzaHVmIC1uIDEwMDAwMDAgbGQvMjAyMDA3MDdfcGFuZWxfbWFmLTAuMDVfd2luZG93LTUwa2Jfbm8tbWlzc2luZ19tYWYtbWF4LTAuNTAvJGkuZ2Vuby5sZCA+PiBsZC8yMDIwMDcwN19wYW5lbF9tYWYtMC4wNV93aW5kb3ctNTBrYl9uby1taXNzaW5nX21hZi1tYXgtMC41MF90aGlubmVkLyRpXF8xbS50eHQiOwpkb25lCiMjIHNlbmQgdG8gbG9jYWwKc2NwIC1yIGJyZXR0ZWxsQGViaTovaHBzL3Jlc2VhcmNoMS9iaXJuZXkvdXNlcnMvaWFuL21pa2tfcGFwZXIvbGQvMjAyMDA3MDdfcGFuZWxfbWFmLTAuMDVfd2luZG93LTUwa2Jfbm8tbWlzc2luZ19tYWYtbWF4LTAuNTBfdGhpbm5lZC8gfi9Eb2N1bWVudHMvRGF0YS8yMDIwMDcwN19taWtrX2xkCmBgYAoKIyMgSW1wb3J0IGRhdGEKCmBgYHtyfQpkYXRhX2ZpbGVzIDwtIGxpc3QuZmlsZXMoIn4vRG9jdW1lbnRzL0RhdGEvMjAyMDA3MDdfbWlra19sZC8yMDIwMDcwN19wYW5lbF9tYWYtMC4wNV93aW5kb3ctNTBrYl9uby1taXNzaW5nX21hZi1tYXgtMC41MF90aGlubmVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bGwubmFtZXMgPSBUKQpkYXRhX2ZpbGVzX3RydW5jIDwtIGxpc3QuZmlsZXMoIn4vRG9jdW1lbnRzL0RhdGEvMjAyMDA3MDdfbWlra19sZC8yMDIwMDcwN19wYW5lbF9tYWYtMC4wNV93aW5kb3ctNTBrYl9uby1taXNzaW5nX21hZi1tYXgtMC41MF90aGlubmVkIikKZGF0YV9maWxlc190cnVuYyA8LSBnc3ViKCJfMW0udHh0IiwgIiIsIGRhdGFfZmlsZXNfdHJ1bmMpCiAKZGF0YV9saXN0IDwtIGxhcHBseShkYXRhX2ZpbGVzLCBmdW5jdGlvbihkYXRhX2ZpbGUpewogIGRmIDwtIHJlYWQuZGVsaW0oZGF0YV9maWxlLAogICAgICAgICAgICAgICAgICAgc2VwID0gIlx0IiwKICAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFQpCiAgbmFtZXMoZGYpIDwtIGMoImNociIsICJzbnBfMSIsICJzbnBfMiIsICJjb3VudCIsICJyMiIpCiAgcmV0dXJuKGRmKQp9KQpuYW1lcyhkYXRhX2xpc3QpIDwtIGFzLmludGVnZXIoZGF0YV9maWxlc190cnVuYykKCiMgcmVvcmRlcgpkYXRhX2xpc3QgPC0gZGF0YV9saXN0W29yZGVyKGFzLmludGVnZXIobmFtZXMoZGF0YV9saXN0KSkpXQpgYGAKCiMjIEdldCBkaXN0YW5jZSBtZWFzdXJlCgpgYGB7cn0KZGF0YV9saXN0IDwtIGxhcHBseShkYXRhX2xpc3QsIGZ1bmN0aW9uKGNocil7CiAgY2hyJGRpc3RhbmNlX2tiIDwtIGFicyhjaHIkc25wXzEgLSBjaHIkc25wXzIpIC8gMTAwMAogIHJldHVybihjaHIpCn0pCmBgYAoKIyMgQ29sbGFwc2UgaW50byBzaW5nbGUgREYKCmBgYHtyfQpkYXRhX2RmIDwtIGRwbHlyOjpiaW5kX3Jvd3MoZGF0YV9saXN0KQpgYGAKCiMjIFBsb3QgCgpgYGB7cn0KIyBUUlVFCmRhdGFfZGYgJT4lIAogIGdncGxvdChhZXMoZGlzdGFuY2Vfa2IsIHIyKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDAuMSwgYWxwaGEgPSAwLjAwNSkgKwogIGdlb21fc21vb3RoKHNpemUgPSAwLjUpICsKICB0aGVtZV9idygpICsKICBmYWNldF93cmFwKH5jaHIsIG5yb3cgPSA2LCBuY29sID0gNCkgKwogIHhsYWIoIkRpc3RhbmNlIGJldHdlZW4gU05QcyAoa2IpIikgKwogIHlsYWIocGFyc2UodGV4dCA9ICJyXjIiKSkKYGBgCmBgYHtyfQpnZ3NhdmUoZmlsZW5hbWUgPSBwYXN0ZSgiMjAyMDA3MDlfbGRfZGVjYXlfc3Vic2V0X2FsbGNocl9tYXgtbWFmLTAuNTAiLCAiLnBuZyIsIHNlcCA9ICIiKSwKICAgICAgIGRldmljZSA9ICJwbmciLAogICAgICAgcGF0aCA9ICJ+L0RvY3VtZW50cy9Eb2NzL21lZGFrYVwgcGljcy8yMDIwMDYwMl9taWtrX2dlbm9tZS8iLAogICAgICAgd2lkdGggPSAxNSwKICAgICAgIGhlaWdodCA9IDE1LAogICAgICAgdW5pdHMgPSAiY20iLAogICAgICAgZHBpID0gNTAwKQpgYGAKCiMjIyBSZXJ1biBMRCBzdGF0cyB3aXRoIG1pbiBNQUYgb2YgMC4xIGFuZCBtYXggTUFGIG9mIDAuOSAKCmBgYHtiYXNofQojIG1ha2UgZGlyZWN0b3J5Cm1rZGlyIGxkLzIwMjAwNzA3X3BhbmVsX21hZi0wLjEwX3dpbmRvdy01MGtiX25vLW1pc3NpbmdfbWFmLW1heC0wLjkwLwojIHJ1bgpmb3IgaSBpbiAkKHNlcSAxIDI0KTsgZG8KICBkYXRlX3RvZGF5PSQoZGF0ZSArJyVZJW0lZCcpOwogIGJzdWIgLU0gMzAwMDAgLW8gbG9nLyRkYXRlX3RvZGF5XF9sZF9tYWYtbWF4XyRjaHIub3V0IC1lIGxvZy8kZGF0ZV90b2RheVxfbGRfbWFmLW1heF8kY2hyLmVyciBcCiAgInZjZnRvb2xzIFwKICAgIC0tZ3p2Y2YgdmNmcy9wYW5lbF9uby1zaWJzX2xpbmUtaWRzX25vLW1pc3NpbmcudmNmLmd6IFwKCSAgLS1sZC13aW5kb3ctYnAgNTAwMDAgXAoJICAtLWNociAkaSBcCgkgIC0tbWFmIDAuMTAgXAoJICAtLW1heC1tYWYgMC45MCBcCgkgIC0tbWF4LWFsbGVsZXMgMiBcCgkgIC0tbWluLWFsbGVsZXMgMiBcCgkgIC0tcmVtb3ZlLWluZGVscyBcCgkgIC0tZ2Vuby1yMiBcCgkgIC0tb3V0IGxkLzIwMjAwNzA3X3BhbmVsX21hZi0wLjEwX3dpbmRvdy01MGtiX25vLW1pc3NpbmdfbWFmLW1heC0wLjkwLyRpIjsKZG9uZQpgYGAKCiMjIyMgVGhpbgoKYGBge2Jhc2h9CiMjIGNyZWF0ZSBzZXQgdXAgZGlyZWN0b3J5Cm1rZGlyIGxkLzIwMjAwNzA3X3BhbmVsX21hZi0wLjEwX3dpbmRvdy01MGtiX25vLW1pc3NpbmdfbWFmLW1heC0wLjkwX3RoaW5uZWQvCiMjIEV4dHJhY3QgcmFuZG9tIDFNIHBhaXJzCmZvciBpIGluICQoc2VxIDEgMjQpOyBkbwogIGRhdGVfdG9kYXk9JChkYXRlICsnJVklbSVkJyk7CiAgYnN1YiAtbyBsb2cvJGRhdGVfdG9kYXlcX2xkX3RyaW1fJGkub3V0IC1lIGxvZy8kZGF0ZV90b2RheVxfbGRfdHJpbV8kaS5lcnIgXAogICJoZWFkIC0xIGxkLzIwMjAwNzA3X3BhbmVsX21hZi0wLjEwX3dpbmRvdy01MGtiX25vLW1pc3NpbmdfbWFmLW1heC0wLjkwLyRpLmdlbm8ubGQgPiBsZC8yMDIwMDcwN19wYW5lbF9tYWYtMC4xMF93aW5kb3ctNTBrYl9uby1taXNzaW5nX21hZi1tYXgtMC45MF90aGlubmVkLyRpXF8xbS50eHQgJiYgXAogIHNodWYgLW4gMTAwMDAwMCBsZC8yMDIwMDcwN19wYW5lbF9tYWYtMC4xMF93aW5kb3ctNTBrYl9uby1taXNzaW5nX21hZi1tYXgtMC45MC8kaS5nZW5vLmxkID4+IGxkLzIwMjAwNzA3X3BhbmVsX21hZi0wLjEwX3dpbmRvdy01MGtiX25vLW1pc3NpbmdfbWFmLW1heC0wLjkwX3RoaW5uZWQvJGlcXzFtLnR4dCI7CmRvbmUKIyMgc2VuZCB0byBsb2NhbApzY3AgLXIgYnJldHRlbGxAZWJpOi9ocHMvcmVzZWFyY2gxL2Jpcm5leS91c2Vycy9pYW4vbWlra19wYXBlci9sZC8yMDIwMDcwN19wYW5lbF9tYWYtMC4xMF93aW5kb3ctNTBrYl9uby1taXNzaW5nX21hZi1tYXgtMC45MF90aGlubmVkLyB+L0RvY3VtZW50cy9EYXRhLzIwMjAwNzA3X21pa2tfbGQKCgojIyMgTk9URTogd2VpcmQgZG91YmxlIGhlYWRlciBpbiBjaHIxNCBmaWxlLiBSZW1vdmUKaGVhZCAtMSB+L0RvY3VtZW50cy9EYXRhLzIwMjAwNzA3X21pa2tfbGQvMjAyMDA3MDdfcGFuZWxfbWFmLTAuMTBfd2luZG93LTUwa2Jfbm8tbWlzc2luZ19tYWYtbWF4LTAuOTBfdGhpbm5lZC8xNF8xbS50eHQgPiB+L0RvY3VtZW50cy9EYXRhLzIwMjAwNzA3X21pa2tfbGQvMjAyMDA3MDdfcGFuZWxfbWFmLTAuMTBfd2luZG93LTUwa2Jfbm8tbWlzc2luZ19tYWYtbWF4LTAuOTBfdGhpbm5lZC8xNF8xbS50eHQudG1wCmdyZXAgLUYgLXYgIlJeMiIgfi9Eb2N1bWVudHMvRGF0YS8yMDIwMDcwN19taWtrX2xkLzIwMjAwNzA3X3BhbmVsX21hZi0wLjEwX3dpbmRvdy01MGtiX25vLW1pc3NpbmdfbWFmLW1heC0wLjkwX3RoaW5uZWQvMTRfMW0udHh0ID4+IH4vRG9jdW1lbnRzL0RhdGEvMjAyMDA3MDdfbWlra19sZC8yMDIwMDcwN19wYW5lbF9tYWYtMC4xMF93aW5kb3ctNTBrYl9uby1taXNzaW5nX21hZi1tYXgtMC45MF90aGlubmVkLzE0XzFtLnR4dC50bXAgJiYgbXYgfi9Eb2N1bWVudHMvRGF0YS8yMDIwMDcwN19taWtrX2xkLzIwMjAwNzA3X3BhbmVsX21hZi0wLjEwX3dpbmRvdy01MGtiX25vLW1pc3NpbmdfbWFmLW1heC0wLjkwX3RoaW5uZWQvMTRfMW0udHh0LnRtcCB+L0RvY3VtZW50cy9EYXRhLzIwMjAwNzA3X21pa2tfbGQvMjAyMDA3MDdfcGFuZWxfbWFmLTAuMTBfd2luZG93LTUwa2Jfbm8tbWlzc2luZ19tYWYtbWF4LTAuOTBfdGhpbm5lZC8xNF8xbS50eHQKYGBgCgojIyBJbXBvcnQgZGF0YQoKYGBge3J9CmRhdGFfZmlsZXMgPC0gbGlzdC5maWxlcygifi9Eb2N1bWVudHMvRGF0YS8yMDIwMDcwN19taWtrX2xkLzIwMjAwNzA3X3BhbmVsX21hZi0wLjEwX3dpbmRvdy01MGtiX25vLW1pc3NpbmdfbWFmLW1heC0wLjkwX3RoaW5uZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgZnVsbC5uYW1lcyA9IFQpCmRhdGFfZmlsZXNfdHJ1bmMgPC0gbGlzdC5maWxlcygifi9Eb2N1bWVudHMvRGF0YS8yMDIwMDcwN19taWtrX2xkLzIwMjAwNzA3X3BhbmVsX21hZi0wLjEwX3dpbmRvdy01MGtiX25vLW1pc3NpbmdfbWFmLW1heC0wLjkwX3RoaW5uZWQiKQpkYXRhX2ZpbGVzX3RydW5jIDwtIGdzdWIoIl8xbS50eHQiLCAiIiwgZGF0YV9maWxlc190cnVuYykKCmRhdGFfbGlzdCA8LSBsYXBwbHkoZGF0YV9maWxlcywgZnVuY3Rpb24oZGF0YV9maWxlKXsKICBkZiA8LSByZWFkLmRlbGltKGRhdGFfZmlsZSwKICAgICAgICAgICAgICAgICAgIHNlcCA9ICJcdCIsCiAgICAgICAgICAgICAgICAgICBoZWFkZXIgPSBUKQogIG5hbWVzKGRmKSA8LSBjKCJjaHIiLCAic25wXzEiLCAic25wXzIiLCAiY291bnQiLCAicjIiKQojICBkZiRzbnBfMSA8LSBhcy5pbnRlZ2VyKGRmJHNucF8xKQojICBkZiRzbnBfMiA8LSBhcy5pbnRlZ2VyKGRmJHNucF8yKQojICBkZiRjaHIgPC0gYXMuaW50ZWdlcihkZiRjaHIpCiAgcmV0dXJuKGRmKQp9KQpuYW1lcyhkYXRhX2xpc3QpIDwtIGFzLmludGVnZXIoZGF0YV9maWxlc190cnVuYykKCiMgcmVvcmRlcgpkYXRhX2xpc3QgPC0gZGF0YV9saXN0W29yZGVyKGFzLmludGVnZXIobmFtZXMoZGF0YV9saXN0KSkpXQpgYGAKCiMjIEdldCBkaXN0YW5jZSBtZWFzdXJlCgpgYGB7cn0KZGF0YV9saXN0IDwtIGxhcHBseShkYXRhX2xpc3QsIGZ1bmN0aW9uKGNocil7CiAgY2hyJGRpc3RhbmNlX2tiIDwtIGFicyhjaHIkc25wXzEgLSBjaHIkc25wXzIpIC8gMTAwMAojICBjaHIkY2hyIDwtIGFzLmludGVnZXIoY2hyJGNocikKICByZXR1cm4oY2hyKQp9KQpgYGAKCiMjIENvbGxhcHNlIGludG8gc2luZ2xlIERGCgpgYGB7cn0KZGF0YV9kZiA8LSBkcGx5cjo6YmluZF9yb3dzKGRhdGFfbGlzdCkKYGBgCgojIyBQbG90IGJ5IGNocgoKYGBge3J9CiMgVEVTVAp0ZXN0X2RmIDwtIGRwbHlyOjpzYW1wbGVfbihkYXRhX2RmLCAxMDAwMCkKCnRlc3RfZGYgJT4lIAogIGdncGxvdChhZXMoZGlzdGFuY2Vfa2IsIHIyKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDAuMSwgYWxwaGEgPSAwLjAwNSkgKwogIGdlb21fc21vb3RoKHNpemUgPSAwLjUpICsKICB0aGVtZV9idygpICsKICBmYWNldF93cmFwKH5jaHIsIG5yb3cgPSA2LCBuY29sID0gNCkgKwogIHhsYWIoIkRpc3RhbmNlIGJldHdlZW4gU05QcyAoa2IpIikgKwogIHlsYWIocGFyc2UodGV4dCA9ICJyXjIiKSkKCgpgYGAKCmBgYHtyfQojIFRSVUUKZGF0YV9kZiAlPiUgCiAgZ2dwbG90KGFlcyhkaXN0YW5jZV9rYiwgcjIpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMC4xLCBhbHBoYSA9IDAuMDA1KSArCiAgZ2VvbV9zbW9vdGgoc2l6ZSA9IDAuNSkgKwogIHRoZW1lX2J3KCkgKwogIGZhY2V0X3dyYXAofmNociwgbnJvdyA9IDYsIG5jb2wgPSA0KSArCiAgeGxhYigiRGlzdGFuY2UgYmV0d2VlbiBTTlBzIChrYikiKSArCiAgeWxhYihwYXJzZSh0ZXh0ID0gInJeMiIpKQpgYGAKCmBgYHtyfQpnZ3NhdmUoZmlsZW5hbWUgPSBwYXN0ZSgiMjAyMDA3MTVfbGRfZGVjYXlfc3Vic2V0X2FsbGNocl9taW4tbWFmLTAuMTBfbWF4LW1hZi0wLjkwIiwgIi5wbmciLCBzZXAgPSAiIiksCiAgICAgICBkZXZpY2UgPSAicG5nIiwKICAgICAgIHBhdGggPSAifi9Eb2N1bWVudHMvRG9jcy9tZWRha2FcIHBpY3MvMjAyMDA2MDJfbWlra19nZW5vbWUvIiwKICAgICAgIHdpZHRoID0gMTUsCiAgICAgICBoZWlnaHQgPSAxNSwKICAgICAgIHVuaXRzID0gImNtIiwKICAgICAgIGRwaSA9IDUwMCkKYGBgCgojIyBHZXQgTUFGIHN0YXRzCgojIyMgQ3JlYXRlIFZDRiB3aXRoIE1BRgoKYGBge2Jhc2h9CiMgTm8gbWlzc2luZwpiY2Z0b29scyArZmlsbC10YWdzIFwKICB2Y2ZzL3BhbmVsX25vLXNpYnNfbGluZS1pZHNfbm8tbWlzc2luZy52Y2YuZ3ogXAogIC0tb3V0cHV0LXR5cGUgeiBcCiAgLS1vdXRwdXQgdmNmcy9wYW5lbF9uby1zaWJzX2xpbmUtaWRzX25vLW1pc3Npbmdfd2l0aC1tYWYudmNmLmd6IFwKICAtLSBcCiAgLS10YWdzIE1BRgojIyBDb3VudCBvZiB2YXJpYW50czogMjAsMDg2LDQzMyAgCiMgTm8gbWlzc2luZywgYmlhbGxlbGljIFNOUHMgb25seQpiY2Z0b29scyB2aWV3IFwKICAtLW1pbi1hbGxlbGVzIDIgXAogIC0tbWF4LWFsbGVsZXMgMlwKICAtLXR5cGVzIHNucHMgXAogIC0tb3V0cHV0LXR5cGUgeiBcCiAgLS1vdXRwdXQgdmNmcy9wYW5lbF9uby1zaWJzX2xpbmUtaWRzX25vLW1pc3Npbmdfd2l0aC1tYWZfYmktc25wcy52Y2YuZ3ogXAogIHZjZnMvcGFuZWxfbm8tc2lic19saW5lLWlkc19uby1taXNzaW5nX3dpdGgtbWFmLnZjZi5negojIyBDb3VudCBvZiB2YXJpYW50czogMTYsMDM1LDA1MgpgYGAKCiMjIyBFeHRyYWN0IHJlbGV2YW50IGZpZWxkcwoKYGBge2Jhc2h9CiMgbWFrZSBkaXJlY3RvcnkKbWtkaXIgbWFmCiMgZ2V0IHN0YXRzCmJjZnRvb2xzIHF1ZXJ5IFwKICAtLWZvcm1hdCAnJUNIUk9NXHQlUE9TXHQlSU5GTy9NQUZcbicgXAogIC0tb3V0cHV0IG1hZi8yMDIwMDcwN19tYWYudHh0IFwKICB2Y2ZzL3BhbmVsX25vLXNpYnNfbGluZS1pZHNfbm8tbWlzc2luZ193aXRoLW1hZl9iaS1zbnBzLnZjZi5negogIAojIHNlbmQgdG8gbG9jYWwKc2NwIGJyZXR0ZWxsQGViaTovaHBzL3Jlc2VhcmNoMS9iaXJuZXkvdXNlcnMvaWFuL21pa2tfcGFwZXIvbWFmLzIwMjAwNzA3X21hZi50eHQgfi9Eb2N1bWVudHMvRGF0YS8yMDIwMDcwN19taWtrX2xkCmBgYAoKIyMjIEltcG9ydCB0byBSCgpgYGB7cn0KbWFmX2RhdCA8LSByZWFkLnRhYmxlKCJ+L0RvY3VtZW50cy9EYXRhLzIwMjAwNzA3X21pa2tfbGQvMjAyMDA3MDdfbWFmLnR4dCIsIAogICAgICAgICAgICAgICAgICBoZWFkZXIgPSBGLCBzZXAgPSAiXHQiKQpjb2xuYW1lcyhtYWZfZGF0KSA8LSBjKCJjaHIiLCAicG9zIiwgIm1hZiIpCmBgYAoKIyMjIFBsb3QKCmBgYHtyfQptYWZfZGF0ICU+JSAKICBnZ3Bsb3QoKSArCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSBtYWYsCiAgICAgICAgICAgICAgICAgICAgIHk9Li5jb3VudC4uLzEwMDAwMDApLAogICAgICAgICAgICAgICAgIGJpbnMgPSA0MCwKICAgICAgICAgICAgICAgICBmaWxsID0gIiMyQTlEOEYiLAogICAgICAgICAgICAgICAgIGNvbG91ciA9ICIjMjY0NjUzIikgKwogIHRoZW1lX2J3KCkgKwogIGd1aWRlcyhmaWxsID0gRikgKwogIHhsYWIoIk1pbm9yIGFsbGVsZSBmcmVxdWVuY2llcyIpICsKICB5bGFiKCJDb3VudCAoaW4gbWlsbGlvbnMgb2Ygc2l0ZXMpIikgCmBgYAoKYGBge3J9Cmdnc2F2ZShmaWxlbmFtZSA9IHBhc3RlKCIyMDIwMDcwN19tYWZfZnJlcXMiLCAiLnBuZyIsIHNlcCA9ICIiKSwKICAgICAgIGRldmljZSA9ICJwbmciLAogICAgICAgcGF0aCA9ICJ+L0RvY3VtZW50cy9Eb2NzL21lZGFrYVwgcGljcy8yMDIwMDYwMl9taWtrX2dlbm9tZS8iLAogICAgICAgd2lkdGggPSAyMCwKICAgICAgIGhlaWdodCA9IDEzLAogICAgICAgdW5pdHMgPSAiY20iLAogICAgICAgZHBpID0gNTAwKQpgYGAKCiMjIFZpc3VhbGlzZSB1c2luZyBIYXBsb3ZpZXcKCiMjIyBNYWtlIFBsaW5rIGRhdGFzZXQgd2l0aCBuby1taXNzaW5nIFZDRgoKKipOT1RFKiogTGVzc29ucyBmcm9tIHRoZSBzdGFydCBvZiB0aGUgUGhEOgoK4oCiIE5lZWQgdG8gZmlyc3QgcmVjb2RlIFNOUHMgaW50byB0aGUgMTIzNCBmb3JtYXQuCuKAoiBUaGVuIHJlY29kZSB0aGF0IGludG8gSGFwbG92aWV3IGZvcm1hdC4K4oCiIFJlcGxhY2UgYXN0ZXJpc2tzIHdpdGggMCBpbiBQRUQgZmlsZQoKYGBge2Jhc2h9CiMgbWFrZSBkaXJlY3RvcnkgZm9yIG91dHB1dHMKbWtkaXIgcGxpbmsKIyBydW4gb3ZlciBWQ0Ygd2l0aCBubyBtaXNzaW5nIHNpdGVzCnBsaW5rIFwKICAtLXZjZiB2Y2ZzL3BhbmVsX25vLXNpYnNfbGluZS1pZHNfbm8tbWlzc2luZy52Y2YuZ3ogXAogIC0tbWFmIDAuMDUgXAogIC0tbWFrZS1iZWQgXAogIC0tZG91YmxlLWlkIFwKICAtLXNucHMtb25seSBcCiAgLS1iaWFsbGVsaWMtb25seSBcCiAgLS1jaHIgMS0yNCBcCiAgLS1hbGxvdy1leHRyYS1jaHIgXAogIC0tYWxsZWxlMTIzNCBcCiAgLS1vdXQgcGxpbmsvMjAyMDA3MDdfcGFuZWxfbm8tc2lic19saW5lLWlkc19uby1taXNzaW5nX21hZi0wLjA1XzEyMzQKIyByZWNvZGUgZm9yIEhWCnBsaW5rIFwKICAtLWJmaWxlIHBsaW5rLzIwMjAwNzA3X3BhbmVsX25vLXNpYnNfbGluZS1pZHNfbm8tbWlzc2luZ19tYWYtMC4wNV8xMjM0IFwKICAtLXJlY29kZSBIViBcCiAgLS1tYWYgMC4wNSBcCiAgLS1kb3VibGUtaWQgXAogIC0tc25wcy1vbmx5IFwKICAtLWJpYWxsZWxpYy1vbmx5IFwKICAtLWNociAxLTI0IFwKICAtLWFsbG93LWV4dHJhLWNociBcCiAgLS1vdXQgcGxpbmsvMjAyMDA3MDdfcGFuZWxfbm8tc2lic19saW5lLWlkc19uby1taXNzaW5nX21hZi0wLjA1XzEyMzRfaHYKCiMgcmVwbGFjZSAqIHdpdGggMApmb3IgaSBpbiAkKGZpbmQgcGxpbmsvMjAyMDA3MDdfcGFuZWxfbm8tc2lic19saW5lLWlkc19uby1taXNzaW5nX21hZi0wLjA1XzEyMzRfaHYqLnBlZCk7IGRvIHNlZCAtaSAncy9cKi8wL2cnICRpOyBkb25lCgojIHNlbmQgdG8gbG9jYWwgdG8gcGxheSB3aXRoCnNjcCBicmV0dGVsbEBlYmk6L2hwcy9yZXNlYXJjaDEvYmlybmV5L3VzZXJzL2lhbi9taWtrX3BhcGVyL3BsaW5rLzIwMjAwNzA3X3BhbmVsX25vLXNpYnNfbGluZS1pZHNfbm8tbWlzc2luZ19tYWYtMC4wNV8xMjM0X2h2LmNociogfi9Eb2N1bWVudHMvRGF0YS8yMDIwMDcwN19taWtrX2xkLzIwMjAwNzA3X3BsaW5rCiMgVG9vIG1hbnkgY29tcGFyaXNvbnMgbWFrZXMgSGFwbG92aWV3IGNyYXNoLiBUcnkgdGhpbm5pbmcuCiMjIEZpcnN0IHNlbmQgYmZpbGVzIHRvIGxvY2FsCnNjcCBicmV0dGVsbEBlYmk6L2hwcy9yZXNlYXJjaDEvYmlybmV5L3VzZXJzL2lhbi9taWtrX3BhcGVyL3BsaW5rLzIwMjAwNzA3X3BhbmVsX25vLXNpYnNfbGluZS1pZHNfbm8tbWlzc2luZ19tYWYtMC4wNV8xMjM0Liogfi9Eb2N1bWVudHMvRGF0YS8yMDIwMDcwN19taWtrX2xkLzIwMjAwNzA5X3BsaW5rCiMgcmVjb2RlIGZvciBIViAob24gbG9jYWwpCnBsaW5rIFwKICAtLWJmaWxlIH4vRG9jdW1lbnRzL0RhdGEvMjAyMDA3MDdfbWlra19sZC8yMDIwMDcwOV9wbGluay8yMDIwMDcwN19wYW5lbF9uby1zaWJzX2xpbmUtaWRzX25vLW1pc3NpbmdfbWFmLTAuMDVfMTIzNCBcCiAgLS1yZWNvZGUgSFYgXAogIC0tbWFmIDAuMDUgXAogIC0tZG91YmxlLWlkIFwKICAtLXNucHMtb25seSBcCiAgLS1iaWFsbGVsaWMtb25seSBcCiAgLS1jaHIgMS0yNCBcCiAgLS1hbGxvdy1leHRyYS1jaHIgXAogIC0tdGhpbiAwLjA1IFwKICAtLW91dCB+L0RvY3VtZW50cy9EYXRhLzIwMjAwNzA3X21pa2tfbGQvMjAyMDA3MDlfcGxpbmsvMjAyMDA3MDlfdGhpbm5lZC0wLjA1L3RoaW5uZWQtMC4wNQojIHJlcGxhY2UgKiB3aXRoIDAKZm9yIGkgaW4gJChmaW5kIC9Vc2Vycy9icmV0dGVsbC9Eb2N1bWVudHMvRGF0YS8yMDIwMDcwN19taWtrX2xkLzIwMjAwNzA5X3BsaW5rLzIwMjAwNzA5X3RoaW5uZWQtMC4wNS90aGlubmVkLTAuMDUqLnBlZCk7IGRvIHNlZCAtaSAnLmJhaycgJ3MvXCovMC9nJyAkaTsgZG9uZSAgCiMgcnVuIEhhcGxvdmlldwpqYXZhIC1YbXgyMEcgLWphciB+L0RvY3VtZW50cy9Tb2Z0d2FyZS9IYXBsb3ZpZXcuamFyIFwKICAtcGVkZmlsZSB+L0RvY3VtZW50cy9EYXRhLzIwMjAwNzA3X21pa2tfbGQvMjAyMDA3MDlfcGxpbmsvMjAyMDA3MDlfdGhpbm5lZC0wLjA1L3RoaW5uZWQtMC4wNS5jaHItMjQucGVkIFwKICAtaW5mbyB+L0RvY3VtZW50cy9EYXRhLzIwMjAwNzA3X21pa2tfbGQvMjAyMDA3MDlfcGxpbmsvMjAyMDA3MDlfdGhpbm5lZC0wLjA1L3RoaW5uZWQtMC4wNS5jaHItMjQuaW5mbyBcCiAgLW1heERpc3RhbmNlIDEwMDAgCiMgc3RpbGwgY3Jhc2hlcy4gVHJ5IHdpdGggMC4wMjUKbWtkaXIgfi9Eb2N1bWVudHMvRGF0YS8yMDIwMDcwN19taWtrX2xkLzIwMjAwNzA5X3BsaW5rLzIwMjAwNzA5X3RoaW5uZWQtMC4wMjUKCnBsaW5rIFwKICAtLWJmaWxlIH4vRG9jdW1lbnRzL0RhdGEvMjAyMDA3MDdfbWlra19sZC8yMDIwMDcwOV9wbGluay8yMDIwMDcwN19wYW5lbF9uby1zaWJzX2xpbmUtaWRzX25vLW1pc3NpbmdfbWFmLTAuMDVfMTIzNCBcCiAgLS1yZWNvZGUgSFYgXAogIC0tbWFmIDAuMDUgXAogIC0tZG91YmxlLWlkIFwKICAtLXNucHMtb25seSBcCiAgLS1iaWFsbGVsaWMtb25seSBcCiAgLS1jaHIgMS0yNCBcCiAgLS1hbGxvdy1leHRyYS1jaHIgXAogIC0tdGhpbiAwLjAyNSBcCiAgLS1vdXQgfi9Eb2N1bWVudHMvRGF0YS8yMDIwMDcwN19taWtrX2xkLzIwMjAwNzA5X3BsaW5rLzIwMjAwNzA5X3RoaW5uZWQtMC4wMjUvdGhpbm5lZC0wLjAyNQojIHJlcGxhY2UgKiB3aXRoIDAKZm9yIGkgaW4gJChmaW5kIC9Vc2Vycy9icmV0dGVsbC9Eb2N1bWVudHMvRGF0YS8yMDIwMDcwN19taWtrX2xkLzIwMjAwNzA5X3BsaW5rLzIwMjAwNzA5X3RoaW5uZWQtMC4wMjUvdGhpbm5lZC0wLjAyNSoucGVkKTsgZG8gc2VkIC1pICcuYmFrJyAncy9cKi8wL2cnICRpOyBkb25lICAgCiMgcnVuIEhhcGxvdmlldwpqYXZhIC1YbXgyMEcgLWphciB+L0RvY3VtZW50cy9Tb2Z0d2FyZS9IYXBsb3ZpZXcuamFyIFwKICAtcGVkZmlsZSB+L0RvY3VtZW50cy9EYXRhLzIwMjAwNzA3X21pa2tfbGQvMjAyMDA3MDlfcGxpbmsvMjAyMDA3MDlfdGhpbm5lZC0wLjAyNS90aGlubmVkLTAuMDI1LmNoci0yNC5wZWQgXAogIC1pbmZvIH4vRG9jdW1lbnRzL0RhdGEvMjAyMDA3MDdfbWlra19sZC8yMDIwMDcwOV9wbGluay8yMDIwMDcwOV90aGlubmVkLTAuMDI1L3RoaW5uZWQtMC4wMjUuY2hyLTI0LmluZm8gXAogIC1tYXhEaXN0YW5jZSAxMDAwIAojIENyZWF0ZXMgcGxvdCwgYnV0IGNyYXNoZXMgd2hlbiBzYXZpbmcgaXQuCmBgYAoKIyMjIFRyeSBgZ2FzdG9uYCBwYWNrYWdlCgojIyMjIE1ha2UgbmV3IEJFRCAKYGBge2Jhc2h9Cm1rZGlyIHBsaW5rLzIwMjAwNzE0X3BhbmVsX25vLXNpYnNfbGluZS1pZHNfbm8tbWlzc2luZ19tYWYtMC4wNQogIAojIG1ha2UgQkVEICAKcGxpbmsgXAogIC0tdmNmIHZjZnMvcGFuZWxfbm8tc2lic19saW5lLWlkc19uby1taXNzaW5nLnZjZi5neiBcCiAgLS1tYWYgMC4wNSBcCiAgLS1tYWtlLWJlZCBcCiAgLS1kb3VibGUtaWQgXAogIC0tc25wcy1vbmx5IFwKICAtLWJpYWxsZWxpYy1vbmx5IFwKICAtLWNociAxLTI0IFwKICAtLWFsbG93LWV4dHJhLWNociBcCiAgLS1vdXQgcGxpbmsvMjAyMDA3MTRfcGFuZWxfbm8tc2lic19saW5lLWlkc19uby1taXNzaW5nX21hZi0wLjA1LzIwMjAwNzE0X3BhbmVsX25vLXNpYnNfbGluZS1pZHNfbm8tbWlzc2luZ19tYWYtMC4wNQogIAojIHJlY29kZSBmb3IgMDEyCnBsaW5rIFwKICAtLWJmaWxlIHBsaW5rLzIwMjAwNzE0X3BhbmVsX25vLXNpYnNfbGluZS1pZHNfbm8tbWlzc2luZ19tYWYtMC4wNS8yMDIwMDcxNF9wYW5lbF9uby1zaWJzX2xpbmUtaWRzX25vLW1pc3NpbmdfbWFmLTAuMDUgXAogIC0tcmVjb2RlIEEgXAogIC0tY2hyIDEtMjQgXAogIC0tYWxsb3ctZXh0cmEtY2hyIFwKICAtLW91dCBwbGluay8yMDIwMDcxNF9wYW5lbF9uby1zaWJzX2xpbmUtaWRzX25vLW1pc3NpbmdfbWFmLTAuMDUvMjAyMDA3MTRfcGFuZWxfbm8tc2lic19saW5lLWlkc19uby1taXNzaW5nX21hZi0wLjA1X3JlY29kZS0wMTIKICAKIyByZWNvZGUgZm9yIDAxMiB0cmFuc3Bvc2VkCnBsaW5rIFwKICAtLWJmaWxlIHBsaW5rLzIwMjAwNzE0X3BhbmVsX25vLXNpYnNfbGluZS1pZHNfbm8tbWlzc2luZ19tYWYtMC4wNS8yMDIwMDcxNF9wYW5lbF9uby1zaWJzX2xpbmUtaWRzX25vLW1pc3NpbmdfbWFmLTAuMDUgXAogIC0tcmVjb2RlIEEtdHJhbnNwb3NlIFwKICAtLWNociAxLTI0IFwKICAtLWFsbG93LWV4dHJhLWNociBcCiAgLS1vdXQgcGxpbmsvMjAyMDA3MTRfcGFuZWxfbm8tc2lic19saW5lLWlkc19uby1taXNzaW5nX21hZi0wLjA1LzIwMjAwNzE0X3BhbmVsX25vLXNpYnNfbGluZS1pZHNfbm8tbWlzc2luZ19tYWYtMC4wNV9yZWNvZGUtMDEyICAKICAKIyBzZW5kIHRvIGxvY2FsCnNjcCBicmV0dGVsbEBlYmk6L2hwcy9yZXNlYXJjaDEvYmlybmV5L3VzZXJzL2lhbi9taWtrX3BhcGVyL3BsaW5rLzIwMjAwNzE0X3BhbmVsX25vLXNpYnNfbGluZS1pZHNfbm8tbWlzc2luZ19tYWYtMC4wNS8yMDIwMDcxNF9wYW5lbF9uby1zaWJzX2xpbmUtaWRzX25vLW1pc3NpbmdfbWFmLTAuMDVfcmVjb2RlLTAxMi5yYXcgfi9Eb2N1bWVudHMvRGF0YS8yMDIwMDcwN19taWtrX2xkLzIwMjAwNzE0X3BsaW5rCgpzY3AgYnJldHRlbGxAZWJpOi9ocHMvcmVzZWFyY2gxL2Jpcm5leS91c2Vycy9pYW4vbWlra19wYXBlci9wbGluay8yMDIwMDcxNF9wYW5lbF9uby1zaWJzX2xpbmUtaWRzX25vLW1pc3NpbmdfbWFmLTAuMDUvMjAyMDA3MTRfcGFuZWxfbm8tc2lic19saW5lLWlkc19uby1taXNzaW5nX21hZi0wLjA1X3JlY29kZS0wMTIudHJhdyB+L0RvY3VtZW50cy9EYXRhLzIwMjAwNzA3X21pa2tfbGQvMjAyMDA3MTRfcGxpbmsKCnNjcCBicmV0dGVsbEBlYmk6L2hwcy9yZXNlYXJjaDEvYmlybmV5L3VzZXJzL2lhbi9taWtrX3BhcGVyL3BsaW5rLzIwMjAwNzE0X3BhbmVsX25vLXNpYnNfbGluZS1pZHNfbm8tbWlzc2luZ19tYWYtMC4wNS8yMDIwMDcxNF9wYW5lbF9uby1zaWJzX2xpbmUtaWRzX25vLW1pc3NpbmdfbWFmLTAuMDUuYmltIH4vRG9jdW1lbnRzL0RhdGEvMjAyMDA3MDdfbWlra19sZC8yMDIwMDcxNF9wbGluawoKc2NwIGJyZXR0ZWxsQGViaTovaHBzL3Jlc2VhcmNoMS9iaXJuZXkvdXNlcnMvaWFuL21pa2tfcGFwZXIvcGxpbmsvMjAyMDA3MTRfcGFuZWxfbm8tc2lic19saW5lLWlkc19uby1taXNzaW5nX21hZi0wLjA1LzIwMjAwNzE0X3BhbmVsX25vLXNpYnNfbGluZS1pZHNfbm8tbWlzc2luZ19tYWYtMC4wNS5mYW0gfi9Eb2N1bWVudHMvRGF0YS8yMDIwMDcwN19taWtrX2xkLzIwMjAwNzE0X3BsaW5rCmBgYAoKIyMjIFJlYWQgaW4gZGF0YQpgYGB7cn0KbGlicmFyeShnYXN0b24pCmxpYnJhcnkodGlkeXZlcnNlKQoKbWlrayA8LSByZWFkLnRhYmxlKCJ+L0RvY3VtZW50cy9EYXRhLzIwMjAwNzA3X21pa2tfbGQvMjAyMDA3MTRfcGxpbmsvMjAyMDA3MTRfcGFuZWxfbm8tc2lic19saW5lLWlkc19uby1taXNzaW5nX21hZi0wLjA1X3JlY29kZS0wMTIudHJhdyIsCiAgICAgICAgICAgICAgICAgICBoZWFkZXIgPSBUKQoKIyBCSU0KbWlray5iaW0gPC0gcmVhZC50YWJsZSgifi9Eb2N1bWVudHMvRGF0YS8yMDIwMDcwN19taWtrX2xkLzIwMjAwNzE0X3BsaW5rLzIwMjAwNzE0X3BhbmVsX25vLXNpYnNfbGluZS1pZHNfbm8tbWlzc2luZ19tYWYtMC4wNS5iaW0iLAogICAgICAgICAgICAgICAgICAgICAgIGhlYWRlciA9IEYsCiAgICAgICAgICAgICAgICAgICAgICAgY29sLm5hbWVzID0gYygiY2hyIiwgImlkIiwgImRpc3QiLCAicG9zIiwgIkExIiwgIkEyIikpCgojIEZBTQptaWtrLmZhbSA8LSByZWFkLnRhYmxlKCJ+L0RvY3VtZW50cy9EYXRhLzIwMjAwNzA3X21pa2tfbGQvMjAyMDA3MTRfcGxpbmsvMjAyMDA3MTRfcGFuZWxfbm8tc2lic19saW5lLWlkc19uby1taXNzaW5nX21hZi0wLjA1LmZhbSIsCiAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVyID0gRiwKICAgICAgICAgICAgICAgICAgICAgICBjb2wubmFtZXMgPSBjKCJmYW1pZCIsICJpZCIsICJmYXRoZXIiLCAibW90aGVyIiwgInNleCIsICJwaGVubyIpKQoKYGBgCgojIyMgUHJlcHJvY2Vzc2luZwoKYGBge3J9CiMgcmVuYW1lIHNhbXBsZSBJRHMKbWlray5nZW4gPC0gbWlrawpjb2xuYW1lcyhtaWtrLmdlbilbNzpuY29sKG1pa2suZ2VuKV0gPC0gIG1pa2suZmFtJGlkCiMgcmVtb3ZlIHVubmVlZGVkIGNvbHVtbnMKbWlray5nZW4gPC0gbWlray5nZW5bLCBjKDEsIDc6bmNvbChtaWtrLmdlbikpXQojIHNwbGl0IGJ5IGNocm9tb3NvbWUKbWlray5nZW5fbHN0IDwtIHNwbGl0KG1pa2suZ2VuLCBmID0gbWlray5nZW4kQ0hSKQojIHJlbW92ZSBDSFIgY29sdW1uCm1pa2suZ2VuX2xzdCA8LSBsYXBwbHkobWlray5nZW5fbHN0LCBmdW5jdGlvbihjaHIpewogIGNociRDSFIgPC0gTlVMTAogIHJldHVybihjaHIpCn0pCgojIHNwbGl0IEJJTSBieSBjaHIgYXMgd2VsbAojIyBnZXQgY291bnRzCiNtaWtrLmJpbSAlPiUgZ3JvdXBfYnkoY2hyKSAlPiUgY291bnQKIyMgc3BsaXQgYnkgY2hyCm1pa2suYmltX2xzdCA8LSBzcGxpdChtaWtrLmJpbSwgZiA9IG1pa2suYmltJGNocikKYGBgCgojIyMgVGVzdAoKYGBge3J9CnNldC5zZWVkKDQ1KQp0YXJnX2luZCA8LSBzb3J0KHNhbXBsZShucm93KG1pa2suZ2VuX2xzdCRgOGApLCAxMDAwKSkKIyBwdWxsIG91dCA1MCBTTlBzCm1pa2suZ2VuXzggPC0gbWlray5nZW5fbHN0JGA4YFt0YXJnX2luZCwgXQptaWtrLmdlbl84IDwtIHQoYXMubWF0cml4KG1pa2suZ2VuXzgpKQptaWtrLmJpbV84IDwtIG1pa2suYmltX2xzdCRgOGBbdGFyZ19pbmQsIF0KIyBjcmVhdGUgYmVkIG1hdHJpeAp4IDwtIGFzLmJlZC5tYXRyaXgobWlray5nZW5fOCwgYmltID0gbWlray5iaW1fOCkKIyBjb21wdXRlIExECmxkLnggPC0gZ2FzdG9uOjpMRCh4LCBjKDEsbmNvbCh4KSkpCiMgcmVwbGFjZSBOYU5zIHdpdGggMApsZC54W3doaWNoKGlzLm5hKGxkLngpKV0gPC0gMAojIHBsb3QKTEQucGxvdCggbGQueCwKICAgICAgICAgc25wLnBvc2l0aW9ucyA9IHhAc25wcyRwb3MsIAogICAgICAgICBtYXguZGlzdCA9IDEwMDAwMDAsCiAgICAgICAgIHdyaXRlLmxkID0gTlVMTCwKICAgICAgICAgd3JpdGUuc25wLmlkID0gRiwKICAgICAgICAgcGRmLmZpbGUgPSAifi9Eb2N1bWVudHMvRG9jcy9tZWRha2EgcGljcy8yMDIwMDYwMl9taWtrX2dlbm9tZS8yMDIwMDcxNF90ZXN0LnBkZiIpCmBgYApXT1JLUyEKClJ1biBvbiBhbGwgY2hycwoKYGBge3J9CiMgZ2V0IHZlY3RvciBvZiBzZWVkcyAKc2V0LnNlZWQoNSkKc2VlZHMgPC0gc2FtcGxlKHNlcSgxLCAxMDApLCAyNCkKIyBydW4gb3ZlciBsaXN0CmNvdW50ZXIgPC0gMApsYXBwbHkobWlray5nZW5fbHN0LCBmdW5jdGlvbihjaHIpewogIGNvdW50ZXIgPDwtIGNvdW50ZXIgKyAxCiAgIyBnZXQgc2VlZAogIHNldC5zZWVkKHNlZWRzW2NvdW50ZXJdKQogIHRhcmdfaW5kIDwtIHNvcnQoc2FtcGxlKG5yb3cobWlray5nZW5fbHN0W1tjb3VudGVyXV0pLCAxMDAwKSkKICAjIHB1bGwgb3V0IDUwIFNOUHMKICBtaWtrLmdlbiA8LSBtaWtrLmdlbl9sc3RbW2NvdW50ZXJdXVt0YXJnX2luZCwgXQogIG1pa2suZ2VuIDwtIHQoYXMubWF0cml4KG1pa2suZ2VuKSkKICBtaWtrLmJpbSA8LSBtaWtrLmJpbV9sc3RbW2NvdW50ZXJdXVt0YXJnX2luZCwgXQogICMgY3JlYXRlIGJlZCBtYXRyaXgKICB4IDwtIGFzLmJlZC5tYXRyaXgobWlray5nZW4sIGJpbSA9IG1pa2suYmltKQogICMgY29tcHV0ZSBMRAogIGxkLnggPC0gZ2FzdG9uOjpMRCh4LCBjKDEsbmNvbCh4KSkpCiAgIyByZXBsYWNlIE5hTnMgd2l0aCAwCiAgbGQueFt3aGljaChpcy5uYShsZC54KSldIDwtIDAKICAjIHBsb3QKICBMRC5wbG90KGxkLngsCiAgICAgICAgICBzbnAucG9zaXRpb25zID0geEBzbnBzJHBvcywgCiAgICAgICAgICBtYXguZGlzdCA9IDEwMDAwMDAsCiAgICAgICAgICB3cml0ZS5sZCA9IE5VTEwsCiAgICAgICAgICB3cml0ZS5zbnAuaWQgPSBGLAogICAgICAgICAgcGRmLmZpbGUgPSBwYXN0ZSgifi9Eb2N1bWVudHMvRG9jcy9tZWRha2EgcGljcy8yMDIwMDYwMl9taWtrX2dlbm9tZS8iLAogICAgICAgICAgICAgICAgICAgICAgICAgICBnc3ViKCItIiwgIiIsIFN5cy5EYXRlKCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiX2NociIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvdW50ZXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICIucGRmIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VwID0gIiIpKQp9KQoKYGBgCgojIyMgR2V0IEJFRCBtYXRyaXggZm9yIGVhY2ggY2hyCgpgYGB7cn0Kc2V0LnNlZWQoNSkKc2VlZHMgPC0gc2FtcGxlKHNlcSgxLCAxMDApLCAyNCkKCmNvdW50ZXIgPC0gMAptaWtrX2JlZF9sc3QgPC0gbGFwcGx5KG1pa2suZ2VuX2xzdCwgZnVuY3Rpb24oY2hyKXsKICBjb3VudGVyIDw8LSBjb3VudGVyICsgMQogICMgdHVybiBjaHIgaW50byBsaXN0CiAgY2hyIDwtIGxpc3QoKQogIAogICMgZ2V0IGJlZCBtYXRyaXgKICAjIyBzZXQgdXAgR0VOIGFuZCBCSU0gZmlsZXMKICBtaWtrLmdlbiA8LSBtaWtrLmdlbl9sc3RbW2NvdW50ZXJdXQogIG1pa2suZ2VuIDwtIHQoYXMubWF0cml4KG1pa2suZ2VuKSkKICBtaWtrLmJpbSA8LSBtaWtrLmJpbV9sc3RbW2NvdW50ZXJdXQogICMjIGZvcm0gQkVEIG1hdHJpeAogIHggPC0gZ2FzdG9uOjphcy5iZWQubWF0cml4KG1pa2suZ2VuLCBiaW0gPSBtaWtrLmJpbSkgIAogIGNocltbImJlZF9tYXQiXV0gPC0geCAKCiAgIyBnZXQgTEQgbWF0cml4CiAgIyMgZ2V0IHNlZWQKICBzZXQuc2VlZChzZWVkc1tjb3VudGVyXSkKICB0YXJnX2luZCA8LSBzb3J0KHNhbXBsZShucm93KG1pa2suZ2VuX2xzdFtbY291bnRlcl1dKSwgMTAwMCkpCiAgY2hyW1sidGFyZ2V0X3NucHNfaW5kZXhlcyJdXSA8LSB0YXJnX2luZAogICMjIHB1bGwgb3V0IHNlbGVjdCBTTlBzCiAgbWlray5nZW4gPC0gbWlray5nZW5fbHN0W1tjb3VudGVyXV1bdGFyZ19pbmQsIF0KICBtaWtrLmdlbiA8LSB0KGFzLm1hdHJpeChtaWtrLmdlbikpCiAgbWlray5iaW0gPC0gbWlray5iaW1fbHN0W1tjb3VudGVyXV1bdGFyZ19pbmQsIF0KICAjIGNyZWF0ZSBiZWQgbWF0cml4CiAgeCA8LSBhcy5iZWQubWF0cml4KG1pa2suZ2VuLCBiaW0gPSBtaWtrLmJpbSkKICAjIGNvbXB1dGUgTEQKICBsZC54IDwtIGdhc3Rvbjo6TEQoeCwgYygxLG5jb2woeCkpKQogIGNocltbIkxEIl1dIDwtIGxkLngKICByZXR1cm4oY2hyKQojICAjIHJlcGxhY2UgTmFOcyB3aXRoIDAKIyAgbGQueFt3aGljaChpcy5uYShsZC54KSldIDwtIDAKfSkKYGBgCgojIyMgUHVsbCBvdXQgYWxsIFNOUFMKCmBgYHtyfQphbGxfc25wcyA8LSBsYXBwbHkobWlra19iZWRfbHN0LCBmdW5jdGlvbih4KXsKICB4IDwtIHgkYmVkX21hdEBzbnBzCiAgcmV0dXJuKHgpCn0pCmFsbF9zbnBzIDwtIGRwbHlyOjpiaW5kX3Jvd3MoYWxsX3NucHMpCiMgNDQ0IGhhdmUgbWlzc2luZyB2YWx1ZXM6Cmxlbmd0aCh3aGljaChpcy5uYShhbGxfc25wcyRtYWYpKSkKIyByZW1vdmUKYWxsX3NucHMgPC0gYWxsX3NucHNbd2hpY2goIWlzLm5hKGFsbF9zbnBzJG1hZikpLCBdCiMgd2hpY2ggb25lcyBoYXZlIE4yID09IDYzPwpWaWV3KGFsbF9zbnBzW3doaWNoKGFsbF9zbnBzJE4yID09IDYzKSwgXSkKdW5pcXVlKGFsbF9zbnBzJGNoclt3aGljaChhbGxfc25wcyROMiA9PSA2MyldKQojIGp1c3QgaW4gQ2hyIDI0LiBDaGVjayBvdXQgZGlzdHJpYnV0aW9uCmhpc3QoYWxsX3NucHMkTjJbYWxsX3NucHMkY2hyID09IDI0XSkKIyBob3cgbWFueSBoYXZlIGEgTUFGIDwgMC4wNT8KbGVuZ3RoKHdoaWNoKGFsbF9zbnBzJG1hZiA8IDAuMDUpKQojIE5lYXJseSAxMCUhIAojIFNwbGl0IGJhY2sgYW5kIGdldCBpbmRleGVzIHNvIHdlIGNhbiByZW1vdmUgdGhlbSBiZWZvcmUgcnVubmluZyB0aGUgTEQgcGxvdHMgYWdhaW4KYWxsX3NucHNfbHN0IDwtIHNwbGl0KGFsbF9zbnBzLCBmID0gYWxsX3NucHMkY2hyKQpzbnBzX3RvX3JlbW92ZSA8LSBsYXBwbHkoYWxsX3NucHNfbHN0LCBmdW5jdGlvbih4KXsKICB3aGljaCh4JG1hZiA8IDAuMDUpCn0pCiMgT25seSBpbiBjaHJzIDIzIGFuZCAyNC4KIyBUaGlzIGxvb2tzIHByZXR0eSB3ZWlyZCB0b28uLi4KVmlldyhhbGxfc25wc1thbGxfc25wcyRtYWYgPCAwLjA1LCBdKQoKIyBUcnkgY2FsY3VsYXRpbmcgbWFmIG1hbnVhbGx5IHRvIHNlZSBpZiBpdCdzIGNvcnJlY3QKYWxsX3NucHMkbWFmX21hbnVhbCA8LSBpZmVsc2UoYWxsX3NucHMkTjEgPT0gNjMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDAuNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGFsbF9zbnBzJE4wID4gYWxsX3NucHMkTjIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoKGFsbF9zbnBzJE4yKjIpICsgYWxsX3NucHMkTjEpIC8gMTI2LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKChhbGxfc25wcyROMCoyKSArIGFsbF9zbnBzJE4xKSAvIDEyNikpCiMgaG93IG1hbnkgYXJlIGRpZmZlcmVudD8KbGVuZ3RoKHdoaWNoKGFsbF9zbnBzJG1hZl9tYW51YWwgIT0gYWxsX3NucHMkbWFmKSkKVmlldyhhbGxfc25wc1t3aGljaChhbGxfc25wcyRtYWZfbWFudWFsICE9IGFsbF9zbnBzJG1hZiksIF0pCiMganVzdCBjaGVjayB0aGF0IGFsbCBhZGQgdXAgdG8gNjMKd2hpY2goYWxsX3NucHMkTjAgKyBhbGxfc25wcyROMSArIGFsbF9zbnBzJE4yICE9IDYzKQojIFllcC4KIyBhbnkgc3RpbGwgdW5kZXIgMC4wNT8Kd2hpY2goYWxsX3NucHMkbWFmX21hbnVhbCA8IDAuMDUpCiMgZGFtbWl0LiBXaGljaCBvbmVzPwp1bmlxdWUoYWxsX3NucHMkY2hyW3doaWNoKGFsbF9zbnBzJG1hZl9tYW51YWwgPCAwLjA1KV0pCiMgSnVzdCBpbiBjaHIgMjQuIFdlaXJkLiBNdXN0IGJlIGNhdXNlZCBieSBQbGluayBub3QgaGFuZGxpbmcgMjQgYXV0b3NvbWVzLgpgYGAKCiMjIyBNYWtlIE1BRiBwbG90IHdpdGgganVzdCB0aGVzZQoKIyMjIFBsb3QKCmBgYHtyfQphbGxfc25wcyAlPiUgCiAgZ2dwbG90KCkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh4ID0gbWFmX21hbnVhbCwKICAgICAgICAgICAgICAgICAgICAgeT0uLmNvdW50Li4vMTAwMDAwMCksCiAgICAgICAgICAgICAgICAgYmlucyA9IDQwLAogICAgICAgICAgICAgICAgIGZpbGwgPSAiI2Y0YTI2MSIsCiAgICAgICAgICAgICAgICAgY29sb3VyID0gIiNlNzZmNTEiKSArCiAgdGhlbWVfYncoKSArCiAgZ3VpZGVzKGZpbGwgPSBGKSArCiAgeGxhYigiTWlub3IgYWxsZWxlIGZyZXF1ZW5jaWVzIikgKwogIHlsYWIoIkNvdW50IChpbiBtaWxsaW9ucyBvZiBzaXRlcykiKSAKYGBgCgojIyMgUHVsbCBvdXQgZW50cmllcyB3aXRoIExEIG9mIDEKCiMjIyMgVEVTVApgYGB7cn0KIyBnZXQgZGF0YSBmcmFtZSBvZiBtYXRyaXggaW5kaWNlcyB3aXRoIFJeMiBvZiAxCnRlc3QgPC0gZGF0YS5mcmFtZSh3aGljaChtaWtrX2JlZF9sc3RbWyIxIl1dW1siTEQiXV0gPT0gMSwgYXJyLmluZCA9IFQpKQojIHJlbW92ZSBkaWFnb25hbHMKdGVzdCA8LSB0ZXN0W3doaWNoKHRlc3Qkcm93ICE9IHRlc3QkY29sKSwgXQojIGdldCBpbmRpY2VzIGZvciBmdWxsIHNucCBsaXN0CnNucF8xX2luZCA8LSBtaWtrX2JlZF9sc3RbWyIxIl1dW1sidGFyZ2V0X3NucHNfaW5kZXhlcyJdXVt0ZXN0JHJvd10Kc25wXzJfaW5kIDwtIG1pa2tfYmVkX2xzdFtbIjEiXV1bWyJ0YXJnZXRfc25wc19pbmRleGVzIl1dW3Rlc3QkY29sXQojIGdldCBkaXN0YW5jZXMgYmV0d2VlbiB0aG9zZSBzbnBzCmhpZ2hfbGRfZGYgPC0gZGF0YS5mcmFtZShzbnBfMV9wb3MgPSBtaWtrX2JlZF9sc3RbWyIxIl1dJGJlZF9tYXRAc25wcyRwb3Nbc25wXzFfaW5kXSwKICAgICAgICAgICAgICAgICAgICAgICAgIHNucF8yX3BvcyA9IG1pa2tfYmVkX2xzdFtbIjEiXV0kYmVkX21hdEBzbnBzJHBvc1tzbnBfMl9pbmRdLAogICAgICAgICAgICAgICAgICAgICAgICAgc25wXzFfbWFmID0gbWlra19iZWRfbHN0W1siMSJdXSRiZWRfbWF0QHNucHMkbWFmW3NucF8xX2luZF0sCiAgICAgICAgICAgICAgICAgICAgICAgICBzbnBfMl9tYWYgPSBtaWtrX2JlZF9sc3RbWyIxIl1dJGJlZF9tYXRAc25wcyRtYWZbc25wXzJfaW5kXSkKaGlnaF9sZF9kZiRkaXN0YW5jZV9rYiA8LSBhYnMoKGhpZ2hfbGRfZGYkc25wXzJfcG9zIC0gaGlnaF9sZF9kZiRzbnBfMV9wb3MpLzFlNikKYGBgCgojIyMjIFRSVUUKYGBge3J9CmhpZ2hfbGRfbHN0IDwtIGxhcHBseShtaWtrX2JlZF9sc3QsIGZ1bmN0aW9uKHgpewogICMgZ2V0IGRhdGEgZnJhbWUgb2YgbWF0cml4IGluZGljZXMgd2l0aCBSXjIgb2YgMQogIHRlc3QgPC0gZGF0YS5mcmFtZSh3aGljaCh4W1siTEQiXV0gPiAwLjksIGFyci5pbmQgPSBUKSkgIAogICMgcmVtb3ZlIGRpYWdvbmFscwogIHRlc3QgPC0gdGVzdFt3aGljaCh0ZXN0JHJvdyAhPSB0ZXN0JGNvbCksIF0KICAjIGdldCBjb3VudAogIHhbWyJoaWdoX2xkX2NvdW50Il1dIDwtIHRlc3QKICAjIGdldCBpbmRpY2VzIGZvciBmdWxsIHNucCBsaXN0CiAgc25wXzFfaW5kIDwtIG1pa2tfYmVkX2xzdFtbIjEiXV1bWyJ0YXJnZXRfc25wc19pbmRleGVzIl1dW3Rlc3Qkcm93XQogIHNucF8yX2luZCA8LSBtaWtrX2JlZF9sc3RbWyIxIl1dW1sidGFyZ2V0X3NucHNfaW5kZXhlcyJdXVt0ZXN0JGNvbF0gIAogICMgZ2V0IGRpc3RhbmNlcyBiZXR3ZWVuIHRob3NlIHNucHMKICBoaWdoX2xkX2RmIDwtIGRhdGEuZnJhbWUoc25wXzFfcG9zID0gbWlra19iZWRfbHN0W1siMSJdXSRiZWRfbWF0QHNucHMkcG9zW3NucF8xX2luZF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNucF8yX3BvcyA9IG1pa2tfYmVkX2xzdFtbIjEiXV0kYmVkX21hdEBzbnBzJHBvc1tzbnBfMl9pbmRdLAogICAgICAgICAgICAgICAgICAgICAgICAgICBzbnBfMV9tYWYgPSBtaWtrX2JlZF9sc3RbWyIxIl1dJGJlZF9tYXRAc25wcyRtYWZbc25wXzFfaW5kXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgc25wXzJfbWFmID0gbWlra19iZWRfbHN0W1siMSJdXSRiZWRfbWF0QHNucHMkbWFmW3NucF8yX2luZF0pCiAgaGlnaF9sZF9kZiRkaXN0YW5jZV9rYiA8LSBhYnMoKGhpZ2hfbGRfZGYkc25wXzJfcG9zIC0gaGlnaF9sZF9kZiRzbnBfMV9wb3MpLzFlNikKICB4W1siaGlnaF9sZF9kZiJdXSA8LSBoaWdoX2xkX2RmCiAgcmV0dXJuKHgpCn0pCmBgYAoKIyMjIyBDcmVhdGUgREZzIGZvciBMRCBkZWNheQoKIyMjIyMgVEVTVApgYGB7cn0KdGVzdCA8LSBkYXRhLmZyYW1lKGhpZ2hfbGRfbHN0JGAxN2AkTEQpCmNvbG5hbWVzKHRlc3QpIDwtIGhpZ2hfbGRfbHN0JGAxN2AkYmVkX21hdEBzbnBzJHBvc1toaWdoX2xkX2xzdCRgMTdgJHRhcmdldF9zbnBzX2luZGV4ZXNdCnRlc3Qkc25wXzFfcG9zIDwtIGhpZ2hfbGRfbHN0JGAxN2AkYmVkX21hdEBzbnBzJHBvc1toaWdoX2xkX2xzdCRgMTdgJHRhcmdldF9zbnBzX2luZGV4ZXNdCnRlc3QyIDwtIHBpdm90X2xvbmdlcih0ZXN0LAogICAgICAgICAgICAgICAgICAgICAgY29scyA9IC1zbnBfMV9wb3MsCiAgICAgICAgICAgICAgICAgICAgICBuYW1lc190byA9ICJzbnBfMl9wb3MiLAogICAgICAgICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gInIyIikKdGVzdDIkc25wXzFfcG9zIDwtIGFzLmludGVnZXIodGVzdDIkc25wXzFfcG9zKQp0ZXN0MiRzbnBfMl9wb3MgPC0gYXMuaW50ZWdlcih0ZXN0MiRzbnBfMl9wb3MpCnRlc3QyJGRpc3RhbmNlX2tiIDwtIGFicygodGVzdDIkc25wXzFfcG9zIC0gdGVzdDIkc25wXzJfcG9zKS8xMDAwMDAwKQojIHJlbW92ZSBkaWFnb25hbHMKdGVzdDIgPC0gdGVzdDJbdGVzdDIkZGlzdGFuY2Vfa2IgIT0gMCwgXQpgYGAKCiMjIyMjIFRSVUUKYGBge3J9CmNvdW50ZXIgPC0gMApsZF9kZl9sc3QgPC0gbGFwcGx5KGhpZ2hfbGRfbHN0LCBmdW5jdGlvbih4KXsKICBjb3VudGVyIDw8LSBjb3VudGVyICsgMQogIHRlc3QgPC0gZGF0YS5mcmFtZSh4JExEKQogIGNvbG5hbWVzKHRlc3QpIDwtIHgkYmVkX21hdEBzbnBzJHBvc1t4JHRhcmdldF9zbnBzX2luZGV4ZXNdCiAgdGVzdCRzbnBfMV9wb3MgPC0geCRiZWRfbWF0QHNucHMkcG9zW3gkdGFyZ2V0X3NucHNfaW5kZXhlc10KICB0ZXN0MiA8LSBwaXZvdF9sb25nZXIodGVzdCwKICAgICAgICAgICAgICAgICAgICAgICAgY29scyA9IC1zbnBfMV9wb3MsCiAgICAgICAgICAgICAgICAgICAgICAgIG5hbWVzX3RvID0gInNucF8yX3BvcyIsCiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJyMiIpCiAgdGVzdDIkc25wXzFfcG9zIDwtIGFzLmludGVnZXIodGVzdDIkc25wXzFfcG9zKQogIHRlc3QyJHNucF8yX3BvcyA8LSBhcy5pbnRlZ2VyKHRlc3QyJHNucF8yX3BvcykKICB0ZXN0MiRkaXN0YW5jZV9rYiA8LSBhYnMoKHRlc3QyJHNucF8xX3BvcyAtIHRlc3QyJHNucF8yX3BvcykvMTAwMCkKICAjIHJlbW92ZSBkaWFnb25hbHMKICB0ZXN0MiA8LSB0ZXN0Mlt0ZXN0MiRkaXN0YW5jZV9rYiAhPSAwLCBdICAKICAjIGdldCBjaHIKICB0ZXN0MiRjaHIgPC0gZmFjdG9yKG5hbWVzKGhpZ2hfbGRfbHN0KVtjb3VudGVyXSwgbGV2ZWxzID0gc2VxKDEsIDI0KSkKICAjIHB1dCBpbiBvcmRlcgogIHRlc3QyIDwtIHRlc3QyICU+JSBkcGx5cjo6c2VsZWN0KGNociwgc25wXzFfcG9zLCBzbnBfMl9wb3MsIGRpc3RhbmNlX2tiLCByMikKICAjIGFzc2lnbgogIHhbWyJyMl9kZiJdXSA8LSB0ZXN0MgogIHJldHVybih4KQp9KQpgYGAKCiMjIyMgUGxvdAoKYGBge3J9CiMgRXh0cmFjdCBpbnRvIGRhdGEgZnJhbWUKbGRfZGYgPC0gbGFwcGx5KGxkX2RmX2xzdCwgZnVuY3Rpb24oeCl7CiAgeCA8LSB4JHIyX2RmCiAgcmV0dXJuKHgpCn0pCmxkX2RmIDwtIGRwbHlyOjpiaW5kX3Jvd3MobGRfZGYpCiMgcmVtb3ZlIGNvbXBhcmlzb25zIGJleW9uZCA1MGtiCmxkX2RmXzUwa2IgPC0gbGRfZGZbbGRfZGYkZGlzdGFuY2Vfa2IgPCA1MCwgXQoKIyBQbG90CmxkX2RmXzUwa2IgJT4lIAogIGdncGxvdChhZXMoZGlzdGFuY2Vfa2IsIHIyKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDAuMSwgYWxwaGEgPSAwLjUpICsKICBnZW9tX3Ntb290aChzaXplID0gMC41KSArCiAgdGhlbWVfYncoKSArCiAgZmFjZXRfd3JhcCh+Y2hyLCBucm93ID0gNiwgbmNvbCA9IDQpICsKICB4bGFiKCJEaXN0YW5jZSBiZXR3ZWVuIFNOUHMgKGtiKSIpICsKICB5bGFiKHBhcnNlKHRleHQgPSAicl4yIikpCmBgYAoKIyMjIERvIExEIHBsb3RzIGFnYWluLCBleGNsdWRpbmcgTUFGIDwgMC4xMAoKYGBge3J9CiMgZ2V0IHZlY3RvciBvZiBzZWVkcyAKc2V0LnNlZWQoNSkKc2VlZHMgPC0gc2FtcGxlKHNlcSgxLCAxMDApLCAyNCkKIyBydW4gb3ZlciBsaXN0CmNvdW50ZXIgPC0gMApsZF9wbG90X2xzdCA8LSBsYXBwbHkobWlray5nZW5fbHN0LCBmdW5jdGlvbihjaHIpewogIGNociA8LSBsaXN0KCkKICBjb3VudGVyIDw8LSBjb3VudGVyICsgMQogIAogICMgY3JlYXRlIEJFRCBNQVQgZnJvbSBmdWxsIGZpbGVzCiAgbWlray5nZW4gPC0gbWlray5nZW5fbHN0W1tjb3VudGVyXV0KICBtaWtrLmdlbiA8LSB0KGFzLm1hdHJpeChtaWtrLmdlbikpCiAgbWlray5iaW0gPC0gbWlray5iaW1fbHN0W1tjb3VudGVyXV0KICB4IDwtIGFzLmJlZC5tYXRyaXgobWlray5nZW4sIGJpbSA9IG1pa2suYmltKQogIGNocltbImJlZF9tYXRfZnVsbCJdXSA8LSB4CiAgCiAgIyBnZXQgaW5kZXhlcyB0byBrZWVwCiAgZmlsdF9pbmQgPC0gd2hpY2goeEBzbnBzJG1hZiA+IDAuMTApCiAgCiAgIyBmaWx0ZXIgZnJvbSBvcmlnaW5hbCBmaWxlcyBhbmQgbWFrZSBCRUQgYWdhaW4KICBtaWtrLmdlbl9maWx0IDwtIG1pa2suZ2VuX2xzdFtbY291bnRlcl1dW2ZpbHRfaW5kLCBdCiAgbWlray5nZW5fZmlsdCA8LSB0KGFzLm1hdHJpeChtaWtrLmdlbl9maWx0KSkgIAogIG1pa2suYmltX2ZpbHQgPC0gbWlray5iaW1fbHN0W1tjb3VudGVyXV1bZmlsdF9pbmQsIF0KICB4IDwtIGFzLmJlZC5tYXRyaXgobWlray5nZW5fZmlsdCwgYmltID0gbWlray5iaW1fZmlsdCkKICBjaHJbWyJiZWRfbWF0X2ZpbHQiXV0gPC0geCAgCiAgCiAgIyBnZXQgc2VlZAogIHNldC5zZWVkKHNlZWRzW2NvdW50ZXJdKQogICMgbWFkZSBHRU4gZmlsZSBhZ2FpbgogIG1pa2suZ2VuX2ZpbHQgPC0gbWlray5nZW5fbHN0W1tjb3VudGVyXV1bZmlsdF9pbmQsIF0KICAjIGdldCBzYW1wbGUgaW5kaWNlcwogIHRhcmdfaW5kIDwtIHNvcnQoc2FtcGxlKG5yb3cobWlray5nZW5fZmlsdCksIDEwMDApKQogICMgcHVsbCBvdXQgc2FtcGxlIFNOUHMKICBtaWtrLmdlbl9zYW1wIDwtIG1pa2suZ2VuX2ZpbHRbdGFyZ19pbmQsIF0KICBtaWtrLmdlbl9zYW1wIDwtIHQoYXMubWF0cml4KG1pa2suZ2VuX3NhbXApKQogIG1pa2suYmltX3NhbXAgPC0gbWlray5iaW1fZmlsdFt0YXJnX2luZCwgXQogICMgY3JlYXRlIGJlZCBtYXRyaXgKICB4IDwtIGFzLmJlZC5tYXRyaXgobWlray5nZW5fc2FtcCwgYmltID0gbWlray5iaW1fc2FtcCkKICBjaHJbWyJiZWRfbWF0X3NhbXAiXV0gPC0geAogICMgY29tcHV0ZSBMRAogIGxkLnggPC0gZ2FzdG9uOjpMRCh4LCBjKDEsbmNvbCh4KSkpCiAgIyByZXBsYWNlIE5hTnMgd2l0aCAwCiAgbGQueFt3aGljaChpcy5uYShsZC54KSldIDwtIDAKCiAgIyBwbG90CiMgIExELnBsb3QobGQueCwKIyAgICAgICAgICBzbnAucG9zaXRpb25zID0geEBzbnBzJHBvcywgCiMgICAgICAgICAgbWF4LmRpc3QgPSAxMDAwMDAwLAojICAgICAgICAgIHdyaXRlLmxkID0gTlVMTCwKIyAgICAgICAgICB3cml0ZS5zbnAuaWQgPSBGLAojICAgICAgICAgIHBkZi5maWxlID0gcGFzdGUoIn4vRG9jdW1lbnRzL0RvY3MvbWVkYWthIHBpY3MvMjAyMDA2MDJfbWlra19nZW5vbWUvMjAyMDA3MTVfbGRfbWFmLTAuMTAvIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICIyMDIwMDcxNV9jaHIiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgY291bnRlciwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICIucGRmIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcCA9ICIiKSkKICByZXR1cm4oY2hyKQp9KQpgYGAKCiMjIEdldCBtZWFuIFJeMgoKYGBge3J9CmZpbGVfaW4gPC0gIn4vRG9jdW1lbnRzL0RhdGEvMjAyMDA3MDdfbWlra19sZC8yMDIwMDcwN19wYW5lbF9tYWYtMC4xMF93aW5kb3ctNTBrYl9uby1taXNzaW5nX21hZi1tYXgtMC45MF90aGlubmVkLzEwXzFtLnR4dCIKIyBSZWFkIGluIGRhdGEKZGF0YSA8LSByZWFkLmRlbGltKGZpbGVfaW4sCiAgICAgICAgICAgICAgICAgICBzZXAgPSAiXHQiLAogICAgICAgICAgICAgICAgICAgaGVhZGVyID0gRiwKICAgICAgICAgICAgICAgICAgIHNraXAgPSAxKQoKIyBTZXQgY29sdW1uIG5hbWVzCmNvbG5hbWVzKGRhdGEpIDwtIGMoImNociIsICJzbnBfMSIsICJzbnBfMiIsICJjb3VudCIsICJyMiIpCgojIENyZWF0ZSBkaXN0YW5jZSB2YXJpYWJsZXMKZGF0YSRkaXN0YW5jZSA8LSBhYnMoZGF0YSRzbnBfMSAtIGRhdGEkc25wXzIpCmRhdGEkZGlzdGFuY2Vfa2IgPC0gYWJzKGRhdGEkc25wXzEgLSBkYXRhJHNucF8yKSAvIDEwMDAKCiMgQ3JlYXRlIGJpbnMKZGF0YSRiaW5fZGlzdF9rYiA8LSBnZ3Bsb3QyOjpjdXRfaW50ZXJ2YWwoZGF0YSRkaXN0YW5jZV9rYiwgbiA9IDUwLCBsYWJlbHMgPSBGKQpkYXRhJGJpbl9kaXN0IDwtIGdncGxvdDI6OmN1dF9pbnRlcnZhbChkYXRhJGRpc3RhbmNlLCBuID0gNTAwKQoKIyBHZXQgYm91bmRhcmllcwpkYXRhJGJpbiA8LSBnZ3Bsb3QyOjpjdXRfaW50ZXJ2YWwoZGF0YSRkaXN0YW5jZSwgbiA9IDUwMCkKCiMgRXh0cmFjdCBmaXJzdCBib3VuZGFyaWVzCmRhdGEkYmluX2JkciA8LSBhcy5udW1lcmljKHN0cmluZ3I6OnN0cl9zcGxpdChkYXRhJGJpbiwgIiwiLCBzaW1wbGlmeSA9IFQpWywxIF0gJT4lIAogIHN0cmluZ3I6OnN0cl9yZXBsYWNlX2FsbCgiXFwoIiwgIiIpICU+JSAKICBzdHJpbmdyOjpzdHJfcmVwbGFjZV9hbGwoIlxcWyIsICIiKSkKCiMgR3JvdXAgYnkgYmluIGFuZCBnZXQgbWVhbnMKdGVzdCA8LSBkYXRhICU+JSAKICBkcGx5cjo6Z3JvdXBfYnkoYmluX2JkcikgJT4lIAogIGRwbHlyOjpzdW1tYXJpc2UobWVhbiA9IG1lYW4ocjIsIG5hLnJtID0gVCkpCgoKCiMgUGxvdApnZ3Bsb3QodGVzdCkgKwogIGdlb21fbGluZShhZXMoYmluX2JkciwgbWVhbikpCmBgYAoKIyMjIFJ1biBzY3JpcHQgb3ZlciBmdWxsIGZpbGUKClNjcmlwdCBoZXJlOiBgY29kZS9zY3JpcHRzLzIwMjAwNzE1X3IyX2RlY2F5X21lYW4uUmAKCmBgYHtiYXNofQpta2RpciBsZC8yMDIwMDcxNV9tZWFuX3IyCgojIFRFU1QKUnNjcmlwdCAtLXZhbmlsbGEgbWlra19nZW5vbWUvY29kZS9zY3JpcHRzLzIwMjAwNzE1X3IyX2RlY2F5X21lYW4uUiBcCiAgbGQvMjAyMDA3MDdfcGFuZWxfbWFmLTAuMTBfd2luZG93LTUwa2Jfbm8tbWlzc2luZ19tYWYtbWF4LTAuOTAvMTguZ2Vuby5sZCBcCiAgbGQvMjAyMDA3MTVfbWVhbl9yMgojIFdPUktTICAKCiMgVFJVRSAgCmZvciBpIGluICQoZmluZCBsZC8yMDIwMDcwN19wYW5lbF9tYWYtMC4xMF93aW5kb3ctNTBrYl9uby1taXNzaW5nX21hZi1tYXgtMC45MC8qKTsgZG8KICBuYW1lPSQoYmFzZW5hbWUgJGkgfCBjdXQgLWYxIC1kIi4iKTsKICBic3ViIC1NIDUwMDAwIC1uIDQgLW8gbG9nLzIwMjAwNzE1XyRuYW1lXF9tZWFuLXIyLm91dCAtZSBsb2cvMjAyMDA3MTVfJG5hbWVcX21lYW4tcjIuZXJyICJSc2NyaXB0IC0tdmFuaWxsYSBtaWtrX2dlbm9tZS9jb2RlL3NjcmlwdHMvMjAyMDA3MTVfcjJfZGVjYXlfbWVhbi5SICRpIGxkLzIwMjAwNzE1X21lYW5fcjIiOwpkb25lCgojIFB1bGwgdG8gbG9jYWwKc2NwIC1yIGJyZXR0ZWxsQGViaTovaHBzL3Jlc2VhcmNoMS9iaXJuZXkvdXNlcnMvaWFuL21pa2tfcGFwZXIvbGQvMjAyMDA3MTVfbWVhbl9yMi8gfi9Eb2N1bWVudHMvRGF0YS8yMDIwMDcwN19taWtrX2xkLwpgYGAKCiMjIyBSZWFkIGluIGRhdGEKYGBge3J9CmRhdGFfZmlsZXMgPC0gbGlzdC5maWxlcygifi9Eb2N1bWVudHMvRGF0YS8yMDIwMDcwN19taWtrX2xkLzIwMjAwNzE1X21lYW5fcjIvIiwKICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bGwubmFtZXMgPSBUKQpkYXRhX2ZpbGVzX3RydW5jIDwtIGxpc3QuZmlsZXMoIn4vRG9jdW1lbnRzL0RhdGEvMjAyMDA3MDdfbWlra19sZC8yMDIwMDcxNV9tZWFuX3IyLyIpCmRhdGFfZmlsZXNfdHJ1bmMgPC0gZ3N1YigiLnR4dCIsICIiLCBkYXRhX2ZpbGVzX3RydW5jKQoKZGF0YV9saXN0IDwtIGxhcHBseShkYXRhX2ZpbGVzLCBmdW5jdGlvbihkYXRhX2ZpbGUpewogIGRmIDwtIHJlYWQuZGVsaW0oZGF0YV9maWxlLAogICAgICAgICAgICAgICAgICAgc2VwID0gIlx0IiwKICAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFQpCiAgI25hbWVzKGRmKSA8LSBjKCJjaHIiLCAic25wXzEiLCAic25wXzIiLCAiY291bnQiLCAicjIiKQogIHJldHVybihkZikKfSkKbmFtZXMoZGF0YV9saXN0KSA8LSBhcy5pbnRlZ2VyKGRhdGFfZmlsZXNfdHJ1bmMpCgojIHJlb3JkZXIKZGF0YV9saXN0IDwtIGRhdGFfbGlzdFtvcmRlcihhcy5pbnRlZ2VyKG5hbWVzKGRhdGFfbGlzdCkpKV0KCiMgYmluZCBpbnRvIERGCnIyX2RmIDwtIGRwbHlyOjpiaW5kX3Jvd3MoZGF0YV9saXN0LCAuaWQgPSAiY2hyIikKcjJfZGYkY2hyIDwtIGZhY3RvcihyMl9kZiRjaHIsIGxldmVscyA9IHNlcSgxLCAyNCkpCgojIGdldCBrYiBtZWFzdXJlCnIyX2RmJGJpbl9iZHJfa2IgPC0gcjJfZGYkYmluX2JkciAvIDEwMDAKYGBgCgojIyMjIFBsb3QKYGBge3J9CnIyX2RmICU+JSBnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGFlcyhiaW5fYmRyLCBtZWFuLCBjb2xvdXIgPSBjaHIpKSArCiAgdGhlbWVfYncoKSArCiAgeGxhYigiRGlzdGFuY2UgYmVldHdlZW4gU05QcyAoYnApIikgKwogIHlsYWIoYnF1b3RlKC4oIk1lYW4gciIpXjIpKSArCiAgbGFicyhjb2xvdXIgPSAiQ2hyb21vc29tZSIpCmBgYAoKYGBge3J9Cmdnc2F2ZShmaWxlbmFtZSA9IHBhc3RlKCIyMDIwMDcxNV9tZWFuLXIyIiwgIi5wbmciLCBzZXAgPSAiIiksCiAgICAgICBkZXZpY2UgPSAicG5nIiwKICAgICAgIHBhdGggPSAifi9Eb2N1bWVudHMvRG9jcy9tZWRha2FcIHBpY3MvMjAyMDA2MDJfbWlra19nZW5vbWUvIiwKICAgICAgIHdpZHRoID0gMjAsCiAgICAgICBoZWlnaHQgPSAxMywKICAgICAgIHVuaXRzID0gImNtIiwKICAgICAgIGRwaSA9IDUwMCkKYGBgCgojIyMjIEZhY2V0CmBgYHtyfQpyMl9kZiAlPiUgZ2dwbG90KCkgKwogIGdlb21fbGluZShhZXMoYmluX2Jkcl9rYiwgbWVhbiwgY29sb3VyID0gY2hyKSkgKwogIHRoZW1lX2J3KCkgKwogIHhsYWIoIkRpc3RhbmNlIGJlZXR3ZWVuIFNOUHMgKEtiKSIpICsKICB5bGFiKGJxdW90ZSguKCJNZWFuIHIiKV4yKSkgKwogIGZhY2V0X3dyYXAofmNociwgbnJvdyA9IDYsIG5jb2wgPSA0KSArCiAgZ3VpZGVzKGNvbG91ciA9IEYpCmBgYAoKYGBge3J9Cmdnc2F2ZShmaWxlbmFtZSA9IHBhc3RlKCIyMDIwMDcxNV9tZWFuLXIyX2ZhY2V0IiwgIi5wbmciLCBzZXAgPSAiIiksCiAgICAgICBkZXZpY2UgPSAicG5nIiwKICAgICAgIHBhdGggPSAifi9Eb2N1bWVudHMvRG9jcy9tZWRha2FcIHBpY3MvMjAyMDA2MDJfbWlra19nZW5vbWUvIiwKICAgICAgIHdpZHRoID0gMjAsCiAgICAgICBoZWlnaHQgPSAxMywKICAgICAgIHVuaXRzID0gImNtIiwKICAgICAgIGRwaSA9IDUwMCkKYGBgCgojIyMgRG8gYWdhaW4sIGJ1dCB3aXRoIG1heCBkaXN0YW5jZSBvZiAxMDAwIGJwIGFuZCA1MCBiaW5zCgpgYGB7YmFzaH0KbWtkaXIgbGQvMjAyMDA3MTVfbWVhbl9yMl8xa2ItbWF4CiMgVFJVRSAgCmZvciBpIGluICQoZmluZCBsZC8yMDIwMDcwN19wYW5lbF9tYWYtMC4xMF93aW5kb3ctNTBrYl9uby1taXNzaW5nX21hZi1tYXgtMC45MC8qKTsgZG8KICBuYW1lPSQoYmFzZW5hbWUgJGkgfCBjdXQgLWYxIC1kIi4iKTsKICBic3ViIC1NIDMwMDAwIC1uIDQgLW8gbG9nLzIwMjAwNzE1XyRuYW1lXF9tZWFuLXIyXzFrYi1tYXgub3V0IC1lIGxvZy8yMDIwMDcxNV8kbmFtZVxfbWVhbi1yMl8xa2ItbWF4LmVyciAiUnNjcmlwdCAtLXZhbmlsbGEgbWlra19nZW5vbWUvY29kZS9zY3JpcHRzLzIwMjAwNzE1X3IyX2RlY2F5X21lYW5fMWtiLWxpbS5SICRpIGxkLzIwMjAwNzE1X21lYW5fcjJfMWtiLW1heCI7CmRvbmUKCiMgUHVsbCB0byBsb2NhbApzY3AgLXIgYnJldHRlbGxAZWJpOi9ocHMvcmVzZWFyY2gxL2Jpcm5leS91c2Vycy9pYW4vbWlra19wYXBlci9sZC8yMDIwMDcxNV9tZWFuX3IyXzFrYi1tYXgvIH4vRG9jdW1lbnRzL0RhdGEvMjAyMDA3MDdfbWlra19sZC8KYGBgCiAKIyMgR2V0IGhldGVyb3p5Z29zaXR5IHN0YXRzCgpgYGB7YmFzaH0KdmNmdG9vbHMgXAogICAgLS1nenZjZiB2Y2ZzL3BhbmVsX25vLXNpYnNfbGluZS1pZHMudmNmLmd6IFwKICAgIC0taGV0IFwKICAgIC0tb3V0IGhldC8yMDIwMDYwMgpgYGAKCiMjIyBSZWFkIGluIGRhdGEKYGBge3J9CmRhdGFfZmlsZXMgPC0gbGlzdC5maWxlcygifi9Eb2N1bWVudHMvRGF0YS8yMDIwMDcwN19taWtrX2xkLzIwMjAwNzE1X21lYW5fcjJfMWtiLW1heC8iLAogICAgICAgICAgICAgICAgICAgICAgICAgZnVsbC5uYW1lcyA9IFQpCmRhdGFfZmlsZXNfdHJ1bmMgPC0gbGlzdC5maWxlcygifi9Eb2N1bWVudHMvRGF0YS8yMDIwMDcwN19taWtrX2xkLzIwMjAwNzE1X21lYW5fcjJfMWtiLW1heC8iKQpkYXRhX2ZpbGVzX3RydW5jIDwtIGdzdWIoIi50eHQiLCAiIiwgZGF0YV9maWxlc190cnVuYykKCmRhdGFfbGlzdCA8LSBsYXBwbHkoZGF0YV9maWxlcywgZnVuY3Rpb24oZGF0YV9maWxlKXsKICBkZiA8LSByZWFkLmRlbGltKGRhdGFfZmlsZSwKICAgICAgICAgICAgICAgICAgIHNlcCA9ICJcdCIsCiAgICAgICAgICAgICAgICAgICBoZWFkZXIgPSBUKQogICNuYW1lcyhkZikgPC0gYygiY2hyIiwgInNucF8xIiwgInNucF8yIiwgImNvdW50IiwgInIyIikKICByZXR1cm4oZGYpCn0pCm5hbWVzKGRhdGFfbGlzdCkgPC0gYXMuaW50ZWdlcihkYXRhX2ZpbGVzX3RydW5jKQoKIyByZW9yZGVyCmRhdGFfbGlzdCA8LSBkYXRhX2xpc3Rbb3JkZXIoYXMuaW50ZWdlcihuYW1lcyhkYXRhX2xpc3QpKSldCgojIGJpbmQgaW50byBERgpyMl9kZiA8LSBkcGx5cjo6YmluZF9yb3dzKGRhdGFfbGlzdCwgLmlkID0gImNociIpCnIyX2RmJGNociA8LSBmYWN0b3IocjJfZGYkY2hyLCBsZXZlbHMgPSBzZXEoMSwgMjQpKQoKIyBnZXQga2IgbWVhc3VyZQpyMl9kZiRiaW5fYmRyX2tiIDwtIHIyX2RmJGJpbl9iZHIgLyAxMDAwCmBgYAoKIyMjIyBQbG90CmBgYHtyfQpyMl9kZiAlPiUgZ2dwbG90KCkgKwogIGdlb21fbGluZShhZXMoYmluX2JkciwgbWVhbiwgY29sb3VyID0gY2hyKSkgKwogIHRoZW1lX2J3KCkgKwogIHhsYWIoIkRpc3RhbmNlIGJlZXR3ZWVuIFNOUHMgKGJwKSIpICsKICB5bGFiKGJxdW90ZSguKCJNZWFuIHIiKV4yKSkgKwogIGxhYnMoY29sb3VyID0gIkNocm9tb3NvbWUiKQpgYGAKCgpgYGB7cn0KZ2dzYXZlKGZpbGVuYW1lID0gcGFzdGUoIjIwMjAwNzE1X21lYW4tcjJfMWtiLWxpbSIsICIucG5nIiwgc2VwID0gIiIpLAogICAgICAgZGV2aWNlID0gInBuZyIsCiAgICAgICBwYXRoID0gIn4vRG9jdW1lbnRzL0RvY3MvbWVkYWthXCBwaWNzLzIwMjAwNjAyX21pa2tfZ2Vub21lLyIsCiAgICAgICB3aWR0aCA9IDIwLAogICAgICAgaGVpZ2h0ID0gMTMsCiAgICAgICB1bml0cyA9ICJjbSIsCiAgICAgICBkcGkgPSA1MDApCmBgYAoKIyMjIyBObyBndWlkZXMKYGBge3J9CnIyX2RmICU+JSBnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGFlcyhiaW5fYmRyLCBtZWFuLCBjb2xvdXIgPSBjaHIpKSArCiAgdGhlbWVfYncoKSArCiAgeGxhYigiRGlzdGFuY2UgYmVldHdlZW4gU05QcyAoYnApIikgKwogIHlsYWIoYnF1b3RlKC4oIk1lYW4gciIpXjIpKSArCiAgZ3VpZGVzKGNvbG91ciA9IEYpCmBgYAoKCmBgYHtyfQpnZ3NhdmUoZmlsZW5hbWUgPSBwYXN0ZSgiMjAyMDA3MTVfbWVhbi1yMl8xa2ItbGltX25vLWd1aWRlIiwgIi5wbmciLCBzZXAgPSAiIiksCiAgICAgICBkZXZpY2UgPSAicG5nIiwKICAgICAgIHBhdGggPSAifi9Eb2N1bWVudHMvRG9jcy9tZWRha2FcIHBpY3MvMjAyMDA2MDJfbWlra19nZW5vbWUvIiwKICAgICAgIHdpZHRoID0gMjAsCiAgICAgICBoZWlnaHQgPSAxMywKICAgICAgIHVuaXRzID0gImNtIiwKICAgICAgIGRwaSA9IDUwMCkKYGBgCgojIyMgR2V0IGNvdW50cyBvZiBTTlBzIHdoZW4gTUFGIDwgMC4xMAoKYGBge3J9CnN1bSh1bmxpc3QobGFwcGx5KGxkX3Bsb3RfbHN0LCBmdW5jdGlvbih4KSBucm93KHhbWyJiZWRfbWF0X2ZpbHQiXV1Ac25wcykpKSkKYGBgCgoqMjAyMDA3MTUqIEJpcm5leSBHcm91cCBtZWV0aW5nCgpHZXQgaHVtYW4gTEQgcGxvdCDigJMgY29udHJhc3QuIE1ham9yIG9uZSB3ZSB3YW50IHRvIG1ha2UuIEFuZCBpdOKAmXMgbm90IHF1aXRlIGFzIGdvb2QgYXMgRHJvc29waGlsYSBhbmQgYWNjZXB0IHRoYXQuIAoKVHJhY2tpbmcgZG93biB0aGVzZSBMRCBibG9ja3MuIEludmVzdGlnYXRlIGluZGl2aWR1YWxseS4gRmluZCBleHBsYW5hdGlvbiBmb3Igb25lLiBEZXNjcmliZSB0aGUgcmVhc29uIHdoeS4gCgpGb3IgdGhlc2UgdmFyaWFudHMgaW4gdGhlIGJsb2NrcywgdGhlIHNhbXBsZXMgd2lsbCBzcGxpdCBiZSBhbmNlc3RyeS4gQXMgd2UgcmFpc2UgdGhlIE1BRiwgd2UgaGlkZSB0aGUgdW5iYWxhbmNlZCBzY2VuYXJpb3MuIFRha2UgU05QcyBpbiBibG9ja3MuIE1ha2UgYSBtYXRyaXguIFNOUHMgYnkgc2FtcGxlcywgdGhlbiBjbHVzdGVyLiBUcnkgSGNsdXN0LiBIb3BlZnVsbHkgd2UgaGF2ZSBzb21lIG9uIG9uZSBzaWRlIG9mIHRoZSB0cmVlLCBzb21lIG9uIHRoZSBvdGhlci4gVHJlZSB3b27igJl0IGxvb2sgYmFsYW5jZWQsIGJ1dCBob3BlZnVsbHkgd2UgaGF2ZSBhIHNhbXBsZSBvbiBlYWNoIHNpZGUuIAoKVGhlIG90aGVyIHRoaW5nIHRoZXkgY291bGQgYmUgaXMgaW50cm9ncmVzc2lvbiBmcm9tIE5vcnRoZXJuIG1lZGFrYSBsaW5lLiBDYW1lIGluIGFuZCByZWZ1c2VzIHRvIHJlY29tYmluZSB3aXRoIFNvdXRoZXJuIG1lZGFrYS4KCkNvdWxkIGJlIHJlZ2lvbnMgb2YgcGVyc2lzdGVudCBoZXRlcm96eWdvc2l0eT8gU2FtcGxlIHJlZ2lvbnMgb2YgcGVyc2lzdGVudCBoZXRlcm96eWdvc2l0eSBhbmQgbWFrZSBiYW5kYWdlIHBsb3RzIGZvciB0aGVtLiAKCkxldCBGZWxpeCBrbm93IHRoYXQgaXTigJlzIHdvcmtpbmcgb3V0LgoKIyBBQkJBIEJBQkEKCiMjIEdldCBTdGlja2xlYmFjayBkYXRhCgoqIEVuc2VtYmwgcGFnZSBoZXJlOiA8aHR0cHM6Ly9hc2lhLmVuc2VtYmwub3JnL0dhc3Rlcm9zdGV1c19hY3VsZWF0dXMvSW5mby9JbmRleD4uCiogRlRQIGZvciBSZWxlYXNlIDEwMCBoZXJlOiA8ZnRwOi8vZnRwLmVuc2VtYmwub3JnL3B1Yi9yZWxlYXNlLTEwMC9mYXN0YS9nYXN0ZXJvc3RldXNfYWN1bGVhdHVzL2RuYS8+LgoqIEZBU1RBIGhlcmU6IDxmdHA6Ly9mdHAuZW5zZW1ibC5vcmcvcHViL3JlbGVhc2UtMTAwL2Zhc3RhL2dhc3Rlcm9zdGV1c19hY3VsZWF0dXMvZG5hL0dhc3Rlcm9zdGV1c19hY3VsZWF0dXMuQlJPQURTMS5kbmEudG9wbGV2ZWwuZmEuZ3o+CgojIyMgRG93bmxvYWQgdG8gY2x1c3RlcgoKYGBge2Jhc2h9CndnZXQgZnRwOi8vZnRwLmVuc2VtYmwub3JnL3B1Yi9yZWxlYXNlLTEwMC9mYXN0YS9nYXN0ZXJvc3RldXNfYWN1bGVhdHVzL2RuYS9HYXN0ZXJvc3RldXNfYWN1bGVhdHVzLkJST0FEUzEuZG5hLnRvcGxldmVsLmZhLmd6CmBgYAoKCgojIyBDbG9uZSByZXBvCgpgYGB7YmFzaH0KIyBPbiBsb2NhbApjZCB+L0RvY3VtZW50cy9SZXBvc2l0b3JpZXMgIApnaXQgY2xvbmUgaHR0cHM6Ly9naXRodWIuY29tL3NpbW9uaG1hcnRpbi9nZW5vbWljc19nZW5lcmFsCmBgYAoKCgoK